5

Suppose I have a Mat variable small_image with dimensions 98x158x32 (type float). Now I want to zero pad this image (ie. add a border of zeros to the image). I want to add 7 zeros above and below the image, and 12 zeros left and right of the image. The first idea was to use the cv copyMakeBorder (see copyMakeBorder doc), which seems perfect for this:

    int old_size[3];
    old_size[0] = 98;
    old_size[1] = 158;
    old_size[2] = 32;

    int pad_size[3];
    pad_size[0] = old_size[0] + 2 * 7;
    pad_size[1] = old_size[1] + 2 * 12;
    pad_size[2] = old_size[2];

    cv::Mat image_padded(3, pad_size, CV_32FC1, cv::Scalar(0)); //Initialize the larger Mat to 0

    copyMakeBorder(small_image,image_padded,7,7,12,12,BORDER_CONSTANT,Scalar(0));

However, this code gives a memcopy error. Does anyone see the problem here?

The alternative as described in this post does not work either:

cv::Rect roi( cv::Point( 12, 7 ), small_image.size() );
small_image.copyTo( image_padded( roi ) );

It claims that "Assertion failed (m.dims <= 2)", while both Mat variables are 3D matrices.

Any help to achieve the zero padding would be greatly appreciated!

Community
  • 1
  • 1
Knippie
  • 83
  • 2
  • 7
  • 1
    copyMakeBorder is most likely not working since it's designed for 2D matrices representing images (although can be multichannel). What you have here is a 3D Mat. – Andrzej Pronobis May 26 '15 at 23:21

2 Answers2

3

Neither of the methods you described work since they are meant to be used for 2D matrices. You have a 3D Mat which requires that you specify ranges in all three dimensions. You can use the () operator which works with an array of ranges combined with copyTo as in the example below.

#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

int main()
{
  int old_size[3];
  old_size[0] = 5;
  old_size[1] = 5;
  old_size[2] = 2;

  int pad_size[3];
  pad_size[0] = old_size[0] + 2 * 1;
  pad_size[1] = old_size[1] + 2 * 2;
  pad_size[2] = old_size[2];

  cv::Mat small_image(3, old_size, CV_32FC1, cv::Scalar(1));
  cv::Mat image_padded(3, pad_size, CV_32FC1, cv::Scalar(0));

  cv::Range ranges[3];
  ranges[0] = cv::Range(1, old_size[0]+1);
  ranges[1] = cv::Range(2, old_size[1]+2);
  ranges[2] = cv::Range(0, old_size[2]);

  small_image.copyTo(image_padded(ranges));

  for (int i = 0; i < pad_size[0]; i++)
    for (int j = 0; j < pad_size[1]; j++)
      for (int k = 0; k < pad_size[2]; k++)
        std::cout << image_padded.at<float>(i, j, k) << ", ";
}

which will give:

0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0
Andrzej Pronobis
  • 33,828
  • 17
  • 76
  • 92
  • Exactly what I needed and works perfectly. Thank you! – Knippie May 28 '15 at 10:43
  • Good solution! I struggled however with the right initialization of `Mat image_padded`. If you loaded an image via `Mat A; A=imread(..)` you need (at least under Ubuntu) the parameters: `cv::Mat image_padded(2, pad_size, CV_8UC3_U, cv::Scalar(0, 0, 0))` Hope this saves someone's time. – Manu CJ Jul 27 '17 at 15:09
2

We could also use a combination of rowRange and colRange methods to set our region of interest to a subsection of 3 dimensional padded image( all zeros ). That could easily followed by copying unpadded image onto it.

cv::Mat image_padded(3, pad_size, CV_32FC1, cv::Scalar(0));
int xPad = 12;
int yPad = 7;
Mat area = image_padded.rowRange(xPad, xPad + 98).colRange(yPad, yPad + 158);
small_image.copyTo( area );
kiranpradeep
  • 10,859
  • 4
  • 50
  • 82
  • 1
    Curious about the purpose of this 3D image – kiranpradeep May 27 '15 at 04:41
  • Thank you for your suggestion. This indeed seems the most intuitive method. It's not really an image, but rather a 3D matrix containing data. I just renamed the variables to a more general case for this post. Usually, I would perform such operations in Matlab but the project I'm working on limits me to C++ – Knippie May 27 '15 at 10:30