Merge remote-tracking branch 'upstream/3.4' into merge-3.4

pull/16890/head
Alexander Alekhin 5 years ago
commit 0b4c101e8a
  1. 4
      CMakeLists.txt
  2. 10
      apps/CMakeLists.txt
  3. 4
      cmake/OpenCVDetectPython.cmake
  4. 2
      doc/js_tutorials/js_gui/js_image_display/js_image_display.markdown
  5. 4
      doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown
  6. 2
      doc/py_tutorials/py_gui/py_image_display/py_image_display.markdown
  7. 2
      doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown
  8. 2
      doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.markdown
  9. 2
      doc/tutorials/ml/introduction_to_svm/introduction_to_svm.markdown
  10. 2
      doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown
  11. 6
      modules/calib3d/src/quadsubpix.cpp
  12. 169
      modules/dnn/src/layers/recurrent_layers.cpp
  13. 207
      modules/dnn/src/onnx/onnx_importer.cpp
  14. 12
      modules/dnn/test/test_onnx_importer.cpp
  15. 2
      modules/imgproc/src/bilateral_filter.dispatch.cpp
  16. 4
      modules/imgproc/src/box_filter.dispatch.cpp
  17. 6
      modules/imgproc/src/deriv.cpp
  18. 15
      modules/imgproc/src/filter.dispatch.cpp
  19. 2
      modules/imgproc/src/median_blur.dispatch.cpp
  20. 8
      modules/imgproc/src/morph.dispatch.cpp
  21. 2
      modules/imgproc/src/smooth.dispatch.cpp
  22. 33
      modules/imgproc/test/test_filter.cpp
  23. 11
      modules/objdetect/src/qrcode.cpp
  24. 31
      modules/ts/include/opencv2/ts/ts_ext.hpp
  25. 5
      modules/videoio/include/opencv2/videoio.hpp

@ -56,6 +56,10 @@ if(POLICY CMP0056)
cmake_policy(SET CMP0056 NEW) # try_compile(): link flags
endif()
if(POLICY CMP0066)
cmake_policy(SET CMP0066 NEW) # CMake 3.7: try_compile(): use per-config flags, like CMAKE_CXX_FLAGS_RELEASE
endif()
if(POLICY CMP0067)
cmake_policy(SET CMP0067 NEW) # CMake 3.8: try_compile(): honor language standard variables (like C++11)
endif()

@ -1,6 +1,8 @@
add_definitions(-D__OPENCV_BUILD=1)
add_definitions(-D__OPENCV_APPS=1)
string(REPLACE "," ";" OPENCV_INSTALL_APPS_LIST "${OPENCV_INSTALL_APPS_LIST}") # support comma-separated list (,) too
# Unified function for creating OpenCV applications:
# ocv_add_application(tgt [MODULES <m1> [<m2> ...]] SRCS <src1> [<src2> ...])
function(ocv_add_application the_target)
@ -25,12 +27,14 @@ function(ocv_add_application the_target)
set_target_properties(${the_target} PROPERTIES FOLDER "applications")
endif()
if(INSTALL_CREATE_DISTRIB)
if(NOT INSTALL_CREATE_DISTRIB
OR (OPENCV_INSTALL_APPS_LIST STREQUAL "all" OR ";${OPENCV_INSTALL_APPS_LIST};" MATCHES ";${the_target};")
)
install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
elseif(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()
endfunction()

@ -78,10 +78,10 @@ if(NOT ${found})
AND NOT DEFINED ${executable}
)
if(NOT OPENCV_SKIP_PYTHON_WARNING)
message(WARNING "CMake's 'find_host_package(PythonInterp ${__python_package_version})' founds wrong Python version:\n"
message(WARNING "CMake's 'find_host_package(PythonInterp ${__python_package_version})' found wrong Python version:\n"
"PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}\n"
"PYTHON_VERSION_STRING=${PYTHON_VERSION_STRING}\n"
"Consider specify '${executable}' variable via CMake command line or environment variables\n")
"Consider providing the '${executable}' variable via CMake command line or environment variables\n")
endif()
ocv_clear_vars(PYTHONINTERP_FOUND PYTHON_EXECUTABLE PYTHON_VERSION_STRING PYTHON_VERSION_MAJOR PYTHON_VERSION_MINOR PYTHON_VERSION_PATCH)
if(NOT CMAKE_VERSION VERSION_LESS "3.12")

@ -13,7 +13,7 @@ OpenCV.js saves images as cv.Mat type. We use HTML canvas element to transfer cv
or in reverse. The ImageData interface can represent or set the underlying pixel data of an area of a
canvas element.
@sa Please refer to canvas docs for more details.
@note Please refer to canvas docs for more details.
First, create an ImageData obj from canvas:
@code{.js}

@ -83,7 +83,7 @@ use 7x6 grid. (Normally a chess board has 8x8 squares and 7x7 internal corners).
corner points and retval which will be True if pattern is obtained. These corners will be placed in
an order (from left-to-right, top-to-bottom)
@sa This function may not be able to find the required pattern in all the images. So, one good option
@note This function may not be able to find the required pattern in all the images. So, one good option
is to write the code such that, it starts the camera and check each frame for required pattern. Once
the pattern is obtained, find the corners and store it in a list. Also, provide some interval before
reading next frame so that we can adjust our chess board in different direction. Continue this
@ -91,7 +91,7 @@ process until the required number of good patterns are obtained. Even in the exa
are not sure how many images out of the 14 given are good. Thus, we must read all the images and take only the good
ones.
@sa Instead of chess board, we can alternatively use a circular grid. In this case, we must use the function
@note Instead of chess board, we can alternatively use a circular grid. In this case, we must use the function
**cv.findCirclesGrid()** to find the pattern. Fewer images are sufficient to perform camera calibration using a circular grid.
Once we find the corners, we can increase their accuracy using **cv.cornerSubPix()**. We can also

@ -132,7 +132,7 @@ A screen-shot of the window will look like this :
![image](images/matplotlib_screenshot.jpg)
@sa Plenty of plotting options are available in Matplotlib. Please refer to Matplotlib docs for more
@note Plenty of plotting options are available in Matplotlib. Please refer to Matplotlib docs for more
details. Some, we will see on the way.
__warning__

@ -113,7 +113,7 @@ I got following results:
See, even image rotation doesn't affect much on this comparison.
@sa [Hu-Moments](http://en.wikipedia.org/wiki/Image_moment#Rotation_invariant_moments) are seven
@note [Hu-Moments](http://en.wikipedia.org/wiki/Image_moment#Rotation_invariant_moments) are seven
moments invariant to translation, rotation and scale. Seventh one is skew-invariant. Those values
can be found using **cv.HuMoments()** function.

@ -94,7 +94,7 @@ hist is same as we calculated before. But bins will have 257 elements, because N
as 0-0.99, 1-1.99, 2-2.99 etc. So final range would be 255-255.99. To represent that, they also add
256 at end of bins. But we don't need that 256. Upto 255 is sufficient.
@sa Numpy has another function, **np.bincount()** which is much faster than (around 10X)
@note Numpy has another function, **np.bincount()** which is much faster than (around 10X)
np.histogram(). So for one-dimensional histograms, you can better try that. Don't forget to set
minlength = 256 in np.bincount. For example, hist = np.bincount(img.ravel(),minlength=256)

@ -51,7 +51,7 @@ Let's introduce the notation used to define formally a hyperplane:
where \f$\beta\f$ is known as the *weight vector* and \f$\beta_{0}\f$ as the *bias*.
@sa A more in depth description of this and hyperplanes you can find in the section 4.5 (*Separating
@note A more in depth description of this and hyperplanes you can find in the section 4.5 (*Separating
Hyperplanes*) of the book: *Elements of Statistical Learning* by T. Hastie, R. Tibshirani and J. H.
Friedman (@cite HTF01).

@ -164,7 +164,7 @@ Describing the methods goes well beyond the purpose of this tutorial. For that I
the article introducing it. Nevertheless, you can get a good image of it by looking at the OpenCV
implementation below.
@sa
@note
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.

@ -61,13 +61,13 @@ static void orderContours(const std::vector<std::vector<Point> >& contours, Poin
for(i = 0; i < n; i++)
{
size_t ni = contours[i].size();
double min_dist = std::numeric_limits<double>::max();
float min_dist = std::numeric_limits<float>::max();
for(j = 0; j < ni; j++)
{
double dist = norm(Point2f((float)contours[i][j].x, (float)contours[i][j].y) - point);
min_dist = MIN(min_dist, dist);
min_dist = (float)MIN((double)min_dist, dist);
}
order.push_back(std::pair<int, float>((int)i, (float)min_dist));
order.push_back(std::pair<int, float>((int)i, min_dist));
}
std::sort(order.begin(), order.end(), is_smaller);

@ -93,6 +93,7 @@ class LSTMLayerImpl CV_FINAL : public LSTMLayer
float forgetBias, cellClip;
bool useCellClip, usePeephole;
bool reverse; // If true, go in negative direction along the time axis
bool bidirectional; // If true, produces both forward and reversed directions along time axis
public:
@ -101,6 +102,7 @@ public:
{
setParamsFrom(params);
bidirectional = params.get<bool>("bidirectional", false);
if (!blobs.empty())
{
CV_Assert(blobs.size() >= 3);
@ -110,10 +112,11 @@ public:
const Mat& Wh = blobs[0];
const Mat& Wx = blobs[1];
const Mat& bias = blobs[2];
CV_Assert(Wh.dims == 2 && Wx.dims == 2);
CV_Assert(Wh.rows == Wx.rows);
CV_Assert(Wh.rows == 4*Wh.cols);
CV_Assert(Wh.rows == (int)bias.total());
CV_CheckEQ(Wh.dims, 2, "");
CV_CheckEQ(Wx.dims, 2, "");
CV_CheckEQ(Wh.rows, Wx.rows, "");
CV_CheckEQ(Wh.rows, (1 + static_cast<int>(bidirectional))*4*Wh.cols, "");
CV_CheckEQ(Wh.rows, (int)bias.total(), "");
CV_Assert(Wh.type() == Wx.type() && Wx.type() == bias.type());
// Peephole weights.
@ -135,6 +138,7 @@ public:
useCellClip = params.get<bool>("use_cell_clip", false);
usePeephole = params.get<bool>("use_peephole", false);
reverse = params.get<bool>("reverse", false);
CV_Assert(!reverse || !bidirectional);
allocated = false;
outTailShape.clear();
@ -206,6 +210,7 @@ public:
outResShape.push_back(_numSamples);
outResShape.insert(outResShape.end(), outTailShape_.begin(), outTailShape_.end());
outResShape.back() *= (1 + static_cast<int>(bidirectional));
size_t noutputs = produceCellOutput ? 2 : 1;
outputs.assign(noutputs, outResShape);
@ -252,6 +257,7 @@ public:
outTsShape.clear();
outTsShape.push_back(numSamples);
outTsShape.insert(outTsShape.end(), outTailShape.begin(), outTailShape.end());
outTsShape.back() *= (1 + static_cast<int>(bidirectional));
allocated = true;
}
@ -272,91 +278,96 @@ public:
outputs_arr.getMatVector(output);
internals_arr.getMatVector(internals);
const Mat &Wh = blobs[0];
const Mat &Wx = blobs[1];
const Mat &bias = blobs[2];
int numOut = Wh.size[1];
Mat hInternal = internals[0], cInternal = internals[1],
dummyOnes = internals[2], gates = internals[3];
hInternal.setTo(0.);
cInternal.setTo(0.);
dummyOnes.setTo(1.);
int numSamplesTotal = numTimeStamps*numSamples;
Mat xTs = input[0].reshape(1, numSamplesTotal);
Mat hOutTs = output[0].reshape(1, numSamplesTotal);
Mat cOutTs = produceCellOutput ? output[1].reshape(1, numSamplesTotal) : Mat();
int tsStart, tsEnd, tsInc;
if (reverse) {
tsStart = numTimeStamps - 1;
tsEnd = -1;
tsInc = -1;
}
else {
tsStart = 0;
tsEnd = numTimeStamps;
tsInc = 1;
}
for (int ts = tsStart; ts != tsEnd; ts += tsInc)
const int numDirs = 1 + static_cast<int>(bidirectional);
for (int i = 0; i < numDirs; ++i)
{
Range curRowRange(ts*numSamples, (ts + 1)*numSamples);
Mat xCurr = xTs.rowRange(curRowRange);
const Mat &Wh = blobs[0].rowRange(i * blobs[0].rows / numDirs, (i + 1) * blobs[0].rows / numDirs);
const Mat &Wx = blobs[1].rowRange(i * blobs[1].rows / numDirs, (i + 1) * blobs[1].rows / numDirs);
const Mat &bias = blobs[2].colRange(i * blobs[2].cols / numDirs, (i + 1) * blobs[2].cols / numDirs);
int numOut = Wh.size[1];
Mat hInternal = internals[0], cInternal = internals[1],
dummyOnes = internals[2], gates = internals[3];
hInternal.setTo(0.);
cInternal.setTo(0.);
dummyOnes.setTo(1.);
int numSamplesTotal = numTimeStamps*numSamples;
Mat xTs = input[0].reshape(1, numSamplesTotal);
Mat hOutTs = output[0].reshape(1, numSamplesTotal);
hOutTs = hOutTs.colRange(i * hOutTs.cols / numDirs, (i + 1) * hOutTs.cols / numDirs);
Mat cOutTs = produceCellOutput ? output[1].reshape(1, numSamplesTotal) : Mat();
int tsStart, tsEnd, tsInc;
if (reverse || i == 1) {
tsStart = numTimeStamps - 1;
tsEnd = -1;
tsInc = -1;
}
else {
tsStart = 0;
tsEnd = numTimeStamps;
tsInc = 1;
}
for (int ts = tsStart; ts != tsEnd; ts += tsInc)
{
Range curRowRange(ts*numSamples, (ts + 1)*numSamples);
Mat xCurr = xTs.rowRange(curRowRange);
gemm(xCurr, Wx, 1, gates, 0, gates, GEMM_2_T); // Wx * x_t
gemm(hInternal, Wh, 1, gates, 1, gates, GEMM_2_T); //+Wh * h_{t-1}
gemm(dummyOnes, bias, 1, gates, 1, gates); //+b
gemm(xCurr, Wx, 1, gates, 0, gates, GEMM_2_T); // Wx * x_t
gemm(hInternal, Wh, 1, gates, 1, gates, GEMM_2_T); //+Wh * h_{t-1}
gemm(dummyOnes, bias, 1, gates, 1, gates); //+b
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);
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);
if (forgetBias)
add(gateF, forgetBias, gateF);
if (forgetBias)
add(gateF, forgetBias, gateF);
if (usePeephole)
{
Mat gatesIF = gates.colRange(0, 2*numOut);
gemm(cInternal, blobs[3], 1, gateI, 1, gateI);
gemm(cInternal, blobs[4], 1, gateF, 1, gateF);
sigmoid(gatesIF, gatesIF);
}
else
{
Mat gatesIFO = gates.colRange(0, 3*numOut);
sigmoid(gatesIFO, gatesIFO);
}
if (usePeephole)
{
Mat gatesIF = gates.colRange(0, 2*numOut);
gemm(cInternal, blobs[3], 1, gateI, 1, gateI);
gemm(cInternal, blobs[4], 1, gateF, 1, gateF);
sigmoid(gatesIF, gatesIF);
}
else
{
Mat gatesIFO = gates.colRange(0, 3*numOut);
sigmoid(gatesIFO, gatesIFO);
}
tanh(gateG, gateG);
tanh(gateG, gateG);
//compute c_t
multiply(gateF, cInternal, gateF); // f_t (*) c_{t-1}
multiply(gateI, gateG, gateI); // i_t (*) g_t
add(gateF, gateI, cInternal); // c_t = f_t (*) c_{t-1} + i_t (*) g_t
//compute c_t
multiply(gateF, cInternal, gateF); // f_t (*) c_{t-1}
multiply(gateI, gateG, gateI); // i_t (*) g_t
add(gateF, gateI, cInternal); // c_t = f_t (*) c_{t-1} + i_t (*) g_t
if (useCellClip)
{
min(cInternal, cellClip, cInternal);
max(cInternal, -cellClip, cInternal);
}
if (usePeephole)
{
gemm(cInternal, blobs[5], 1, gateO, 1, gateO);
sigmoid(gateO, gateO);
}
if (useCellClip)
{
min(cInternal, cellClip, cInternal);
max(cInternal, -cellClip, cInternal);
}
if (usePeephole)
{
gemm(cInternal, blobs[5], 1, gateO, 1, gateO);
sigmoid(gateO, gateO);
}
//compute h_t
tanh(cInternal, hInternal);
multiply(gateO, hInternal, hInternal);
//compute h_t
tanh(cInternal, hInternal);
multiply(gateO, hInternal, hInternal);
//save results in output blobs
hInternal.copyTo(hOutTs.rowRange(curRowRange));
if (produceCellOutput)
cInternal.copyTo(cOutTs.rowRange(curRowRange));
//save results in output blobs
hInternal.copyTo(hOutTs.rowRange(curRowRange));
if (produceCellOutput)
cInternal.copyTo(cOutTs.rowRange(curRowRange));
}
}
}
};

@ -49,6 +49,11 @@ class ONNXImporter
LayerParams getLayerParams(const opencv_onnx::NodeProto& node_proto);
bool isCeilMode(const LayerParams& layerParams);
void addLayer(Net& dstNet, LayerParams& layerParams,
const opencv_onnx::NodeProto& node_proto,
std::map<std::string, LayerInfo>& layer_id,
std::map<std::string, MatShape>& outShapes);
public:
ONNXImporter(const char *onnxFile)
@ -259,6 +264,42 @@ Mat ONNXImporter::getBlob(const opencv_onnx::NodeProto& node_proto,
return constBlob->second;
}
void ONNXImporter::addLayer(Net& dstNet, LayerParams& layerParams,
const opencv_onnx::NodeProto& node_proto,
std::map<std::string, LayerInfo>& layer_id,
std::map<std::string, MatShape>& outShapes)
{
std::map<std::string, LayerInfo>::iterator layerId;
std::map<std::string, MatShape>::iterator shapeIt;
int id = dstNet.addLayer(layerParams.name, layerParams.type, layerParams);
for (int i = 0; i < node_proto.output_size(); ++i)
{
layer_id.insert(std::make_pair(node_proto.output(i), LayerInfo(id, i)));
}
std::vector<MatShape> layerInpShapes, layerOutShapes, layerInternalShapes;
int inpNum = 0;
for (int j = 0; j < node_proto.input_size(); j++) {
layerId = layer_id.find(node_proto.input(j));
if (layerId != layer_id.end()) {
dstNet.connect(layerId->second.layerId, layerId->second.outputId, id, inpNum);
++inpNum;
// Collect input shapes.
shapeIt = outShapes.find(node_proto.input(j));
CV_Assert(shapeIt != outShapes.end());
layerInpShapes.push_back(shapeIt->second);
}
}
// Compute shape of output blob for this layer.
Ptr<Layer> layer = dstNet.getLayer(id);
layer->getMemoryShapes(layerInpShapes, 0, layerOutShapes, layerInternalShapes);
for (int i = 0; i < node_proto.output_size() && i < (int)layerOutShapes.size(); ++i)
{
outShapes[node_proto.output(i)] = layerOutShapes[i];
}
}
void ONNXImporter::populateNet(Net dstNet)
{
CV_Assert(model_proto.has_graph());
@ -455,6 +496,7 @@ void ONNXImporter::populateNet(Net dstNet)
runLayer(layerParams, inputs, sliced);
CV_Assert(sliced.size() == 1);
constBlobs.insert(std::make_pair(layerParams.name, sliced[0]));
outShapes[layerParams.name] = shape(sliced[0]);
continue;
}
}
@ -579,6 +621,70 @@ void ONNXImporter::populateNet(Net dstNet)
constBlobs.insert(std::make_pair(layerParams.name, layerParams.blobs[0]));
continue;
}
else if (layer_type == "LSTM")
{
LayerParams lstmParams = layerParams;
lstmParams.name += "/lstm";
// https://pytorch.org/docs/stable/nn.html#lstm
CV_Assert(node_proto.input_size() == 7);
Mat Wx = getBlob(node_proto, constBlobs, 1);
Mat Wh = getBlob(node_proto, constBlobs, 2);
Mat b = getBlob(node_proto, constBlobs, 3);
CV_CheckEQ(countNonZero(getBlob(node_proto, constBlobs, 5)), 0, "Unsupported non zero initial_h");
CV_CheckEQ(countNonZero(getBlob(node_proto, constBlobs, 6)), 0, "Unsupported non zero initial_c");
b = b.reshape(1, b.size[0]);
const int numHidden = lstmParams.get<int>("hidden_size");
const int numDirs = Wx.size[0]; // Is 1 for forward only and 2 for bidirectional LSTM.
const int numFeatures = Wx.size[2];
Mat bx = b.colRange(0, b.cols / 2);
Mat bh = b.colRange(b.cols / 2, b.cols);
b = bx + bh;
// IFGO->IGFO
for (int k = 0; k < numDirs; ++k)
{
float* WxData = Wx.ptr<float>(k);
float* WhData = Wh.ptr<float>(k);
float* biasData = b.ptr<float>(k);
for (int j = 0; j < numHidden; ++j)
{
for (int i = 0; i < numFeatures; ++i)
{
std::swap(WxData[(numHidden + j) * numFeatures + i],
WxData[(numHidden * 2 + j) * numFeatures + i]);
}
for (int i = 0; i < numHidden; ++i)
{
std::swap(WhData[(numHidden + j) * numHidden + i],
WhData[(numHidden * 2 + j) * numHidden + i]);
}
std::swap(biasData[numHidden + j], biasData[numHidden * 2 + j]);
}
}
Wx = Wx.reshape(1, Wx.size[0] * Wx.size[1]);
Wh = Wh.reshape(1, Wh.size[0] * Wh.size[1]);
lstmParams.blobs.resize(3);
lstmParams.blobs[0] = Wh;
lstmParams.blobs[1] = Wx;
lstmParams.blobs[2] = b;
lstmParams.set("bidirectional", lstmParams.get<String>("direction", "") == "bidirectional");
node_proto.set_output(0, lstmParams.name); // set different name so output shapes will be registered on that name
addLayer(dstNet, lstmParams, node_proto, layer_id, outShapes);
MatShape lstmShape = outShapes[node_proto.output(0)];
// Add fake 1 as it is done in ONNX
lstmShape.insert(lstmShape.begin() + 1, 1);
layerParams.type = "Reshape";
layerParams.set("dim", DictValue::arrayInt(&lstmShape[0], lstmShape.size()));
node_proto.set_input(0, lstmParams.name); // redirect input to LSTM
node_proto.set_output(0, layerParams.name); // keep origin LSTM's name
}
else if (layer_type == "ImageScaler")
{
const float scale = layerParams.has("scale") ? layerParams.get<float>("scale") : 1.0f;
@ -882,13 +988,38 @@ void ONNXImporter::populateNet(Net dstNet)
{
CV_Assert_N(node_proto.input_size() == 1, layerParams.has("axes"));
DictValue axes_dict = layerParams.get("axes");
if (axes_dict.size() != 1)
CV_Error(Error::StsNotImplemented, "Multidimensional squeeze");
MatShape inpShape = outShapes[node_proto.input(0)];
int axis = axes_dict.getIntValue(0);
layerParams.set("axis", axis - 1);
layerParams.set("end_axis", axis);
layerParams.type = "Flatten";
std::vector<bool> maskedAxes(inpShape.size(), false);
for (int i = 0; i < axes_dict.size(); ++i)
{
int axis = axes_dict.getIntValue(i);
CV_CheckLE(axis, static_cast<int>(inpShape.size()), "Squeeze axis");
maskedAxes[axis] = inpShape[axis] == 1;
}
MatShape outShape;
for (int i = 0; i < inpShape.size(); ++i)
{
if (!maskedAxes[i])
outShape.push_back(inpShape[i]);
}
if (outShape.size() != inpShape.size())
{
layerParams.type = "Reshape";
layerParams.set("dim", DictValue::arrayInt(&outShape[0], outShape.size()));
}
else
layerParams.type = "Identity";
if (constBlobs.find(node_proto.input(0)) != constBlobs.end())
{
Mat inp = getBlob(node_proto, constBlobs, 0);
Mat out = inp.reshape(1, outShape);
out.dims = outShape.size(); // to workaround dims == 1
constBlobs.insert(std::make_pair(layerParams.name, out));
outShapes[layerParams.name] = shape(out);
continue;
}
}
else if (layer_type == "Flatten")
{
@ -1018,9 +1149,17 @@ void ONNXImporter::populateNet(Net dstNet)
else
layerParams.type = "Identity";
}
else if (layer_type == "ConstantOfShape")
else if (layer_type == "ConstantOfShape" || layer_type == "ConstantFill")
{
float fill_value = layerParams.blobs.empty() ? 0 : layerParams.blobs[0].at<float>(0, 0);
float fill_value;
if (!layerParams.blobs.empty())
{
CV_Assert(!layerParams.has("value"));
fill_value = layerParams.blobs[0].at<float>(0, 0);
}
else
fill_value = layerParams.get("value", 0);
MatShape inpShape = getBlob(node_proto, constBlobs, 0);
for (int i = 0; i < inpShape.size(); i++)
CV_CheckGT(inpShape[i], 0, "");
@ -1032,17 +1171,30 @@ void ONNXImporter::populateNet(Net dstNet)
else if (layer_type == "Gather")
{
CV_Assert(node_proto.input_size() == 2);
CV_Assert(layerParams.has("axis"));
Mat input = getBlob(node_proto, constBlobs, 0);
Mat indexMat = getBlob(node_proto, constBlobs, 1);
CV_Assert_N(indexMat.type() == CV_32S, indexMat.total() == 1);
int index = indexMat.at<int>(0);
int axis = layerParams.get<int>("axis");
std::vector<cv::Range> ranges(input.dims, Range::all());
ranges[axis] = Range(index, index + 1);
Mat out;
if (layerParams.has("axis"))
{
int axis = layerParams.get<int>("axis");
std::vector<cv::Range> ranges(input.dims, Range::all());
ranges[axis] = Range(index, index + 1);
Mat out = input(ranges);
out = input(ranges);
}
else
{
CV_Assert(index < input.total());
const int dims = input.dims;
input = input.reshape(1, 1);
input.dims = 2;
out = input.reshape(1, 1).colRange(index, index + 1);
out.dims = dims;
}
constBlobs.insert(std::make_pair(layerParams.name, out));
continue;
}
@ -1145,34 +1297,7 @@ void ONNXImporter::populateNet(Net dstNet)
layerParams.blobs.push_back(getBlob(node_proto, constBlobs, j));
}
}
int id = dstNet.addLayer(layerParams.name, layerParams.type, layerParams);
for (int i = 0; i < node_proto.output_size(); ++i)
{
layer_id.insert(std::make_pair(node_proto.output(i), LayerInfo(id, i)));
}
std::vector<MatShape> layerInpShapes, layerOutShapes, layerInternalShapes;
int inpNum = 0;
for (int j = 0; j < node_proto.input_size(); j++) {
layerId = layer_id.find(node_proto.input(j));
if (layerId != layer_id.end()) {
dstNet.connect(layerId->second.layerId, layerId->second.outputId, id, inpNum);
++inpNum;
// Collect input shapes.
shapeIt = outShapes.find(node_proto.input(j));
CV_Assert(shapeIt != outShapes.end());
layerInpShapes.push_back(shapeIt->second);
}
}
// Compute shape of output blob for this layer.
Ptr<Layer> layer = dstNet.getLayer(id);
layer->getMemoryShapes(layerInpShapes, 0, layerOutShapes, layerInternalShapes);
for (int i = 0; i < node_proto.output_size() && i < (int)layerOutShapes.size(); ++i)
{
outShapes[node_proto.output(i)] = layerOutShapes[i];
}
addLayer(dstNet, layerParams, node_proto, layer_id, outShapes);
}
}

@ -430,6 +430,8 @@ TEST_P(Test_ONNX_layers, Reshape)
TEST_P(Test_ONNX_layers, Squeeze)
{
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target == DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
testONNXModels("squeeze");
}
@ -476,6 +478,16 @@ TEST_P(Test_ONNX_layers, Split_EltwiseMax)
testONNXModels("split_max");
}
TEST_P(Test_ONNX_layers, LSTM)
{
testONNXModels("lstm", npy, 0, 0, false, false);
}
TEST_P(Test_ONNX_layers, LSTM_bidirectional)
{
testONNXModels("lstm_bidirectional", npy, 0, 0, false, false);
}
INSTANTIATE_TEST_CASE_P(/*nothing*/, Test_ONNX_layers, dnnBackendsAndTargets());
class Test_ONNX_nets : public Test_ONNX_layers

@ -406,6 +406,8 @@ void bilateralFilter( InputArray _src, OutputArray _dst, int d,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
_dst.create( _src.size(), _src.type() );
CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),

@ -443,6 +443,8 @@ void boxFilter(InputArray _src, OutputArray _dst, int ddepth,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
CV_OCL_RUN(_dst.isUMat() &&
(borderType == BORDER_REPLICATE || borderType == BORDER_CONSTANT ||
borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101),
@ -514,6 +516,8 @@ void sqrBoxFilter(InputArray _src, OutputArray _dst, int ddepth,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
int srcType = _src.type(), sdepth = CV_MAT_DEPTH(srcType), cn = CV_MAT_CN(srcType);
Size size = _src.size();

@ -416,6 +416,8 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
if (ddepth < 0)
ddepth = sdepth;
@ -468,6 +470,8 @@ void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
if (ddepth < 0)
ddepth = sdepth;
@ -785,6 +789,8 @@ void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
if (ddepth < 0)
ddepth = sdepth;

@ -169,6 +169,9 @@ int FilterEngine::start(const Size& _wholeSize, const Size& sz, const Point& ofs
{
CV_INSTRUMENT_REGION();
CV_Assert(!sz.empty());
CV_Assert(!_wholeSize.empty());
CV_CPU_DISPATCH(FilterEngine__start, (*this, _wholeSize, sz, ofs),
CV_CPU_DISPATCH_MODES_ALL);
}
@ -176,6 +179,11 @@ int FilterEngine::start(const Size& _wholeSize, const Size& sz, const Point& ofs
int FilterEngine::start(const Mat& src, const Size &wsz, const Point &ofs)
{
CV_INSTRUMENT_REGION();
CV_Assert(!src.empty());
CV_Assert(!wsz.empty());
start( wsz, src.size(), ofs);
return startY - ofs.y;
}
@ -1398,6 +1406,9 @@ void filter2D(InputArray _src, OutputArray _dst, int ddepth,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
CV_Assert(!_kernel.empty());
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
ocl_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType))
@ -1429,6 +1440,10 @@ void sepFilter2D(InputArray _src, OutputArray _dst, int ddepth,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
CV_Assert(!_kernelX.empty());
CV_Assert(!_kernelY.empty());
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))

@ -280,6 +280,8 @@ void medianBlur( InputArray _src0, OutputArray _dst, int ksize )
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src0.empty());
CV_Assert( (ksize % 2 == 1) && (_src0.dims() <= 2 ));
if( ksize <= 1 || _src0.empty() )

@ -939,6 +939,8 @@ static void morphOp( int op, InputArray _src, OutputArray _dst,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
Mat kernel = _kernel.getMat();
Size ksize = !kernel.empty() ? kernel.size() : Size(3,3);
anchor = normalizeAnchor(anchor, ksize);
@ -1005,6 +1007,8 @@ void erode( InputArray src, OutputArray dst, InputArray kernel,
{
CV_INSTRUMENT_REGION();
CV_Assert(!src.empty());
morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}
@ -1015,6 +1019,8 @@ void dilate( InputArray src, OutputArray dst, InputArray kernel,
{
CV_INSTRUMENT_REGION();
CV_Assert(!src.empty());
morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}
@ -1154,6 +1160,8 @@ void morphologyEx( InputArray _src, OutputArray _dst, int op,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
Mat kernel = _kernel.getMat();
if (kernel.empty())
{

@ -603,6 +603,8 @@ void GaussianBlur(InputArray _src, OutputArray _dst, Size ksize,
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
int type = _src.type();
Size size = _src.size();
_dst.create( size, type );

@ -2323,4 +2323,37 @@ TEST(Imgproc_Pyrdown, issue_12961)
ASSERT_EQ(0.0, cv::norm(dst));
}
// https://github.com/opencv/opencv/issues/16857
TEST(Imgproc, filter_empty_src_16857)
{
#define CV_TEST_EXPECT_EMPTY_THROW(statement) CV_TEST_EXPECT_EXCEPTION_MESSAGE(statement, ".empty()")
Mat src, dst, dst2;
CV_TEST_EXPECT_EMPTY_THROW(bilateralFilter(src, dst, 5, 50, 20));
CV_TEST_EXPECT_EMPTY_THROW(blur(src, dst, Size(3, 3)));
CV_TEST_EXPECT_EMPTY_THROW(boxFilter(src, dst, CV_8U, Size(3, 3)));
CV_TEST_EXPECT_EMPTY_THROW(sqrBoxFilter(src, dst, CV_8U, Size(3, 3)));
CV_TEST_EXPECT_EMPTY_THROW(medianBlur(src, dst, 3));
CV_TEST_EXPECT_EMPTY_THROW(GaussianBlur(src, dst, Size(3, 3), 0));
CV_TEST_EXPECT_EMPTY_THROW(cv::filter2D(src, dst, CV_8U, Mat_<float>::zeros(Size(3, 3))));
CV_TEST_EXPECT_EMPTY_THROW(sepFilter2D(src, dst, CV_8U, Mat_<float>::zeros(Size(3, 1)), Mat_<float>::zeros(Size(1, 3))));
CV_TEST_EXPECT_EMPTY_THROW(Sobel(src, dst, CV_8U, 1, 1));
CV_TEST_EXPECT_EMPTY_THROW(spatialGradient(src, dst, dst2));
CV_TEST_EXPECT_EMPTY_THROW(Scharr(src, dst, CV_8U, 1, 1));
CV_TEST_EXPECT_EMPTY_THROW(Laplacian(src, dst, CV_8U));
CV_TEST_EXPECT_EMPTY_THROW(cv::dilate(src, dst, Mat())); // cvtest:: by default
CV_TEST_EXPECT_EMPTY_THROW(cv::erode(src, dst, Mat())); // cvtest:: by default
CV_TEST_EXPECT_EMPTY_THROW(morphologyEx(src, dst, MORPH_OPEN, Mat()));
//debug: CV_TEST_EXPECT_EMPTY_THROW(blur(Mat_<uchar>(Size(3,3)), dst, Size(3, 3)));
EXPECT_TRUE(src.empty());
EXPECT_TRUE(dst.empty());
EXPECT_TRUE(dst2.empty());
}
}} // namespace

@ -122,9 +122,16 @@ void QRDetect::init(const Mat& src, double eps_vertical_, double eps_horizontal_
eps_vertical = eps_vertical_;
eps_horizontal = eps_horizontal_;
adaptiveThreshold(barcode, bin_barcode, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 83, 2);
adaptiveThreshold(resized_barcode, resized_bin_barcode, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 83, 2);
if (!barcode.empty())
adaptiveThreshold(barcode, bin_barcode, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 83, 2);
else
bin_barcode.release();
if (!resized_barcode.empty())
adaptiveThreshold(resized_barcode, resized_bin_barcode, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 83, 2);
else
resized_bin_barcode.release();
}
vector<Vec3d> QRDetect::searchHorizontalLines()

@ -161,4 +161,35 @@ bool checkBigDataTests();
#undef TEST_P
#define TEST_P(test_case_name, test_name) CV__TEST_P(test_case_name, test_name, Body, CV__TEST_BODY_IMPL)
#define CV_TEST_EXPECT_EXCEPTION_MESSAGE(statement, msg) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::internal::AlwaysTrue()) { \
const char* msg_ = msg; \
bool hasException = false; \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} \
catch (const cv::Exception& e) { \
if (NULL == strstr(e.what(), msg_)) \
ADD_FAILURE() << "Unexpected cv::Exception is raised: " << #statement << "\n Expected message substring: '" << msg_ << "'. Actual message:\n" << e.what(); \
hasException = true; \
} \
catch (const std::exception& e) { \
ADD_FAILURE() << "Unexpected std::exception is raised: " << #statement << "\n" << e.what(); \
hasException = true; \
} \
catch (...) { \
ADD_FAILURE() << "Unexpected C++ exception is raised: " << #statement; \
hasException = true; \
} \
if (!hasException) { \
goto GTEST_CONCAT_TOKEN_(gtest_label_test_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_test_, __LINE__): \
ADD_FAILURE() << "Failed: Expected: " #statement " throws an '" << msg << "' exception.\n" \
" Actual: it doesn't."
#endif // OPENCV_TS_EXT_HPP

@ -639,7 +639,8 @@ public:
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
@sa cv::VideoCaptureAPIs
*/
CV_WRAP explicit VideoCapture(const String& filename, int apiPreference = CAP_ANY);
@ -651,7 +652,7 @@ public:
@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_DSHOW or cv::CAP_MSMF or cv::CAP_V4L.
@sa The list of supported API backends cv::VideoCaptureAPIs
@sa cv::VideoCaptureAPIs
*/
CV_WRAP explicit VideoCapture(int index, int apiPreference = CAP_ANY);

Loading…
Cancel
Save