diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index 7488351456..81d0f8da8d 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -695,6 +695,16 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN */ CV_EXPORTS_W Mat blobFromImage(InputArray image, double scalefactor=1.0, const Size& size = Size(), const Scalar& mean = Scalar(), bool swapRB=true, bool crop=true); + + /** @brief Creates 4-dimensional blob from image. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + */ + CV_EXPORTS void blobFromImage(InputArray image, OutputArray blob, double scalefactor=1.0, + const Size& size = Size(), const Scalar& mean = Scalar(), + bool swapRB=true, bool crop=true); + + /** @brief Creates 4-dimensional blob from series of images. Optionally resizes and * crops @p images from center, subtract @p mean values, scales values by @p scalefactor, * swap Blue and Red channels. @@ -711,9 +721,18 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN * If @p crop is false, direct resize without cropping and preserving aspect ratio is performed. * @returns 4-dimansional Mat with NCHW dimensions order. */ - CV_EXPORTS_W Mat blobFromImages(const std::vector& images, double scalefactor=1.0, + CV_EXPORTS_W Mat blobFromImages(InputArrayOfArrays images, double scalefactor=1.0, Size size = Size(), const Scalar& mean = Scalar(), bool swapRB=true, bool crop=true); + /** @brief Creates 4-dimensional blob from series of images. + * @details This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + */ + CV_EXPORTS void blobFromImages(InputArrayOfArrays images, OutputArray blob, + double scalefactor=1.0, Size size = Size(), + const Scalar& mean = Scalar(), bool swapRB=true, bool crop=true); + + /** @brief Convert all weights of Caffe network to half precision floating point. * @param src Path to origin model from Caffe framework contains single * precision floating point weights (usually has `.caffemodel` extension). diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 051044af8d..a588fb3888 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -81,27 +81,39 @@ namespace }; } -template -static String toString(const T &v) -{ - std::ostringstream ss; - ss << v; - return ss.str(); -} - Mat blobFromImage(InputArray image, double scalefactor, const Size& size, const Scalar& mean, bool swapRB, bool crop) { CV_TRACE_FUNCTION(); - std::vector images(1, image.getMat()); - return blobFromImages(images, scalefactor, size, mean, swapRB, crop); + Mat blob; + blobFromImage(image, blob, scalefactor, size, mean, swapRB, crop); + return blob; } -Mat blobFromImages(const std::vector& images_, double scalefactor, Size size, - const Scalar& mean_, bool swapRB, bool crop) +void blobFromImage(InputArray image, OutputArray blob, double scalefactor, + const Size& size, const Scalar& mean, bool swapRB, bool crop) { CV_TRACE_FUNCTION(); - std::vector images = images_; + std::vector images(1, image.getMat()); + blobFromImages(images, blob, scalefactor, size, mean, swapRB, crop); +} + +Mat blobFromImages(InputArrayOfArrays images, double scalefactor, Size size, + const Scalar& mean, bool swapRB, bool crop) +{ + CV_TRACE_FUNCTION(); + Mat blob; + blobFromImages(images, blob, scalefactor, size, mean, swapRB, crop); + return blob; +} + +void blobFromImages(InputArrayOfArrays images_, OutputArray blob_, double scalefactor, + Size size, const Scalar& mean_, bool swapRB, bool crop) +{ + CV_TRACE_FUNCTION(); + std::vector images; + images_.getMatVector(images); + CV_Assert(!images.empty()); for (int i = 0; i < images.size(); i++) { Size imgSize = images[i].size(); @@ -133,16 +145,15 @@ Mat blobFromImages(const std::vector& images_, double scalefactor, Size siz } size_t i, nimages = images.size(); - if(nimages == 0) - return Mat(); Mat image0 = images[0]; int nch = image0.channels(); CV_Assert(image0.dims == 2); - Mat blob, image; + Mat image; if (nch == 3 || nch == 4) { int sz[] = { (int)nimages, nch, image0.rows, image0.cols }; - blob = Mat(4, sz, CV_32F); + blob_.create(4, sz, CV_32F); + Mat blob = blob_.getMat(); Mat ch[4]; for( i = 0; i < nimages; i++ ) @@ -164,7 +175,8 @@ Mat blobFromImages(const std::vector& images_, double scalefactor, Size siz { CV_Assert(nch == 1); int sz[] = { (int)nimages, 1, image0.rows, image0.cols }; - blob = Mat(4, sz, CV_32F); + blob_.create(4, sz, CV_32F); + Mat blob = blob_.getMat(); for( i = 0; i < nimages; i++ ) { @@ -177,7 +189,6 @@ Mat blobFromImages(const std::vector& images_, double scalefactor, Size siz image.copyTo(Mat(image.rows, image.cols, CV_32F, blob.ptr((int)i, 0))); } } - return blob; } class OpenCLBackendWrapper : public BackendWrapper @@ -886,7 +897,8 @@ struct Net::Impl { LayerPin storedFrom = ld.inputBlobsId[inNum]; if (storedFrom.valid() && !storedFrom.equal(from)) - CV_Error(Error::StsError, "Input #" + toString(inNum) + "of layer \"" + ld.name + "\" already was connected"); + CV_Error(Error::StsError, format("Input #%d of layer \"%s\" already was connected", + inNum, ld.name.c_str())); } ld.inputBlobsId[inNum] = from; @@ -1665,8 +1677,9 @@ struct Net::Impl LayerData &ld = layers[pin.lid]; if ((size_t)pin.oid >= ld.outputBlobs.size()) { - CV_Error(Error::StsOutOfRange, "Layer \"" + ld.name + "\" produce only " + toString(ld.outputBlobs.size()) + - " outputs, the #" + toString(pin.oid) + " was requsted"); + CV_Error(Error::StsOutOfRange, format("Layer \"%s\" produce only %d outputs, " + "the #%d was requsted", ld.name.c_str(), + ld.outputBlobs.size(), pin.oid)); } if (preferableTarget != DNN_TARGET_CPU) { diff --git a/modules/dnn/test/test_misc.cpp b/modules/dnn/test/test_misc.cpp index 2eee54cd9c..f53cdd2941 100644 --- a/modules/dnn/test/test_misc.cpp +++ b/modules/dnn/test/test_misc.cpp @@ -27,4 +27,14 @@ TEST(blobFromImage_4ch, Regression) } } +TEST(blobFromImage, allocated) +{ + int size[] = {1, 3, 4, 5}; + Mat img(size[2], size[3], CV_32FC(size[1])); + Mat blob(4, size, CV_32F); + void* blobData = blob.data; + dnn::blobFromImage(img, blob, 1.0 / 255, Size(), Scalar(), false, false); + ASSERT_EQ(blobData, blob.data); +} + }