Skip to content

Commit 8ef2f71

Browse files
committed
Merge pull request #1236 from arrybn:crop_mean
2 parents fd5431c + ea1670b commit 8ef2f71

File tree

7 files changed

+75
-30
lines changed

7 files changed

+75
-30
lines changed

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,9 +598,37 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
598598
* @warning This function has the same limitations as createTorchImporter().
599599
*/
600600
CV_EXPORTS_W Mat readTorchBlob(const String &filename, bool isBinary = true);
601-
602-
CV_EXPORTS Mat blobFromImage(const Mat& image, double scalefactor=1.0, bool swapRB=true);
603-
CV_EXPORTS Mat blobFromImages(const std::vector<Mat>& image, double scalefactor=1.0, bool swapRB=true);
601+
/** @brief Creates 4-dimensional blob from image. Optionally resizes and crops @p image from center,
602+
* subtract @p mean values, scales values by @p scalefactor, swap Blue and Red channels.
603+
* @param image input image (with 1- or 3-channels).
604+
* @param size spatial size for output image
605+
* @param mean scalar with mean values which are subtracted from channels. Values are intended
606+
* to be in (mean-R, mean-G, mean-B) order if @p image has BGR ordering and @p swapRB is true.
607+
* @param scalefactor multiplier for @p image values.
608+
* @param swapRB flag which indicates that swap first and last channels
609+
* in 3-channel image is necessary.
610+
* @details input image is resized so one side after resize is equal to corresponing
611+
* dimension in @p size and another one is equal or larger. Then, crop from the center is performed.
612+
* @returns 4-dimansional Mat with NCHW dimensions order.
613+
*/
614+
CV_EXPORTS_W Mat blobFromImage(const Mat& image, double scalefactor=1.0, const Size& size = Size(),
615+
const Scalar& mean = Scalar(), bool swapRB=true);
616+
/** @brief Creates 4-dimensional blob from series of images. Optionally resizes and
617+
* crops @p images from center, subtract @p mean values, scales values by @p scalefactor,
618+
* swap Blue and Red channels.
619+
* @param images input images (all with 1- or 3-channels).
620+
* @param size spatial size for output image
621+
* @param mean scalar with mean values which are subtracted from channels. Values are intended
622+
* to be in (mean-R, mean-G, mean-B) order if @p image has BGR ordering and @p swapRB is true.
623+
* @param scalefactor multiplier for @p images values.
624+
* @param swapRB flag which indicates that swap first and last channels
625+
* in 3-channel image is necessary.
626+
* @details input image is resized so one side after resize is equal to corresponing
627+
* dimension in @p size and another one is equal or larger. Then, crop from the center is performed.
628+
* @returns 4-dimansional Mat with NCHW dimensions order.
629+
*/
630+
CV_EXPORTS_W Mat blobFromImages(const std::vector<Mat>& images, double scalefactor=1.0,
631+
Size size = Size(), const Scalar& mean = Scalar(), bool swapRB=true);
604632

605633
//! @}
606634
}

modules/dnn/samples/caffe_googlenet.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,9 @@ int main(int argc, char **argv)
114114
exit(-1);
115115
}
116116

117-
resize(img, img, Size(224, 224)); //GoogLeNet accepts only 224x224 RGB-images
118-
Mat inputBlob = blobFromImage(img); //Convert Mat to batch of images
117+
//GoogLeNet accepts only 224x224 RGB-images
118+
Mat inputBlob = blobFromImage(img, 1, Size(224, 224),
119+
Scalar(104, 117, 123)); //Convert Mat to batch of images
119120
//! [Prepare blob]
120121

121122
//! [Set input blob]

modules/dnn/samples/squeezenet_halide.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ int main(int argc, char **argv)
8989
}
9090

9191
resize(img, img, Size(227, 227)); // SqueezeNet v1.1 predict class by 3x227x227 input image.
92-
Mat inputBlob = blobFromImage(img, 1.0, false); // Convert Mat to 4-dimensional batch.
92+
Mat inputBlob = blobFromImage(img, 1.0, Size(), Scalar(), false); // Convert Mat to 4-dimensional batch.
9393
//! [Prepare blob]
9494

9595
//! [Set input blob]

modules/dnn/samples/torch_enet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ int main(int argc, char **argv)
6969
if (inputImgSize != origSize)
7070
resize(img, img, inputImgSize); //Resize image to input size
7171

72-
Mat inputBlob = blobFromImage(img, 1./255, true); //Convert Mat to image batch
72+
Mat inputBlob = blobFromImage(img, 1./255); //Convert Mat to image batch
7373
//! [Prepare blob]
7474

7575
//! [Set input blob]

modules/dnn/src/dnn.cpp

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <sstream>
4949
#include <iterator>
5050
#include <opencv2/dnn/shape_utils.hpp>
51+
#include <opencv2/imgproc.hpp>
5152

5253
using namespace cv;
5354
using namespace cv::dnn;
@@ -86,14 +87,42 @@ static String toString(const T &v)
8687
return ss.str();
8788
}
8889

89-
Mat blobFromImage(const Mat& image_, double scalefactor, bool swapRB)
90+
Mat blobFromImage(const Mat& image, double scalefactor, const Size& size,
91+
const Scalar& mean, bool swapRB)
9092
{
91-
std::vector<Mat> images(1, image_);
92-
return blobFromImages(images, scalefactor, swapRB);
93+
std::vector<Mat> images(1, image);
94+
return blobFromImages(images, scalefactor, size, mean, swapRB);
9395
}
9496

95-
Mat blobFromImages(const std::vector<Mat>& images, double scalefactor, bool swapRB)
97+
Mat blobFromImages(const std::vector<Mat>& images_, double scalefactor, Size size,
98+
const Scalar& mean_, bool swapRB)
9699
{
100+
std::vector<Mat> images = images_;
101+
for (int i = 0; i < images.size(); i++)
102+
{
103+
Size imgSize = images[i].size();
104+
if (size == Size())
105+
size = imgSize;
106+
if (size != imgSize)
107+
{
108+
float resizeFactor = std::max(size.width / (float)imgSize.width,
109+
size.height / (float)imgSize.height);
110+
resize(images[i], images[i], Size(), resizeFactor, resizeFactor);
111+
Rect crop(Point(0.5 * (images[i].cols - size.width),
112+
0.5 * (images[i].rows - size.height)),
113+
size);
114+
images[i] = images[i](crop);
115+
}
116+
if(images[i].depth() == CV_8U)
117+
images[i].convertTo(images[i], CV_32F);
118+
Scalar mean = mean_;
119+
if (swapRB)
120+
std::swap(mean[0], mean[2]);
121+
122+
images[i] -= mean;
123+
images[i] *= scalefactor;
124+
}
125+
97126
size_t i, nimages = images.size();
98127
if(nimages == 0)
99128
return Mat();
@@ -109,13 +138,7 @@ Mat blobFromImages(const std::vector<Mat>& images, double scalefactor, bool swap
109138

110139
for( i = 0; i < nimages; i++ )
111140
{
112-
Mat image_ = images[i];
113-
if(image_.depth() == CV_8U)
114-
{
115-
image_.convertTo(image, CV_32F, scalefactor);
116-
}
117-
else
118-
image = image_;
141+
image = images[i];
119142
CV_Assert(image.depth() == CV_32F);
120143
nch = image.channels();
121144
CV_Assert(image.dims == 2 && (nch == 3 || nch == 4));
@@ -136,13 +159,7 @@ Mat blobFromImages(const std::vector<Mat>& images, double scalefactor, bool swap
136159

137160
for( i = 0; i < nimages; i++ )
138161
{
139-
Mat image_ = images[i];
140-
if(image_.depth() == CV_8U)
141-
{
142-
image_.convertTo(image, CV_32F, scalefactor);
143-
}
144-
else
145-
image = image_;
162+
Mat image = images[i];
146163
CV_Assert(image.depth() == CV_32F);
147164
nch = image.channels();
148165
CV_Assert(image.dims == 2 && (nch == 1));
@@ -154,7 +171,6 @@ Mat blobFromImages(const std::vector<Mat>& images, double scalefactor, bool swap
154171
return blob;
155172
}
156173

157-
158174
struct LayerPin
159175
{
160176
int lid;

modules/dnn/test/test_caffe_importer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ TEST(Reproducibility_AlexNet, Accuracy)
9494
if (sample.size() != inputSize)
9595
resize(sample, sample, inputSize);
9696

97-
net.setInput(blobFromImage(sample, 1.), "data");
97+
net.setInput(blobFromImage(sample), "data");
9898
Mat out = net.forward("prob");
9999
Mat ref = blobFromNPY(_tf("caffe_alexnet_prob.npy"));
100100
normAssert(ref, out);
@@ -123,7 +123,7 @@ TEST(Reproducibility_FCN, Accuracy)
123123
std::vector<size_t> weights, blobs;
124124
net.getMemoryConsumption(shape(1,3,227,227), layerIds, weights, blobs);
125125

126-
net.setInput(blobFromImage(sample, 1.), "data");
126+
net.setInput(blobFromImage(sample), "data");
127127
Mat out = net.forward("score");
128128
Mat ref = blobFromNPY(_tf("caffe_fcn8s_prob.npy"));
129129
normAssert(ref, out);

modules/dnn/test/test_tf_importer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ TEST(Test_TensorFlow, read_inception)
4040
resize(sample, input, Size(224, 224));
4141
input -= 128; // mean sub
4242

43-
Mat inputBlob = blobFromImage(input, 1.);
43+
Mat inputBlob = blobFromImage(input);
4444

4545
net.setInput(inputBlob, "input");
4646
Mat out = net.forward("softmax2");
@@ -61,7 +61,7 @@ TEST(Test_TensorFlow, inception_accuracy)
6161
Mat sample = imread(_tf("grace_hopper_227.png"));
6262
ASSERT_TRUE(!sample.empty());
6363
resize(sample, sample, Size(224, 224));
64-
Mat inputBlob = blobFromImage(sample, 1.);
64+
Mat inputBlob = blobFromImage(sample);
6565

6666
net.setInput(inputBlob, "input");
6767
Mat out = net.forward("softmax2");

0 commit comments

Comments
 (0)