Confused about how to properly add a white border to my numpy imagearray with numpy.pad

Viewed 2762

I've used openCV2 to load a grayscale image, which I then converted to a numpy.array. Now I want to pad that array with a 'frame' around the image. However, I'm having some trouble dissecting what the numpy manual wants me to do exactly. I tried googling and searching for padding examples, none came up that were relevant for my case.

My current code looks like this:

import numpy as np
img = cv2.imread('Lena.png', )
imgArray = np.array((img))
imgArray = np.pad(imgArray, pad_width=1,mode='constant' ,constant_values=0)
cv2.imshow('Padded', imgArray)
4 Answers

You can do as follows:

import numpy as np
import cv2 

img = cv2.imread('Lena.png', 0)
img = np.pad(img, pad_width=4, mode='constant', constant_values=0)
cv2.imshow('Padded', img)
cv2.waitKey(0)

From the documentation of cv2.imread:

cv2.imread(filename[, flags]) → retval

Parameters:

  • filename – Name of file to be loaded.

  • flags:

Flags specifying the color type of a loaded image:

CV_LOAD_IMAGE_ANYDEPTH - If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.

CV_LOAD_IMAGE_COLOR - If set, always convert image to the color one

CV_LOAD_IMAGE_GRAYSCALE - If set, always convert image to the grayscale one

>0 Return a 3-channel color image. Note In the current implementation the alpha channel, if any, is stripped from the output image. Use negative value if you need the alpha channel.

=0 Return a grayscale image.

<0 Return the loaded image as is (with alpha channel).

With the above code we got the following result:

enter image description here

And another option using np.pad:

As you can see here, you need to supply the axis you want to np.pad. Simply using:

    imgArray = np.pad(imgArray, pad_width=1, mode='constant', constant_values=0)

adds only values to the third axis (i.e. the RGB channel), so that you cannot plot the image any more.

As described in the referenced question, you would need to use the following arguments to you code:

   imgArray = np.pad(imgArray, pad_width=((1,1), (1,1), (0,0)), mode='constant', constant_values=0)

Also see the np.pad documentation:

Number of values padded to the edges of each axis. ((before_1, after_1), … (before_N, after_N)) unique pad widths for each axis. ((before, after),) yields same before and after pad for each axis. (pad,) or int is a shortcut for before = after = pad width for all axes.

This means the first entry of tuple pads the first axis (in case of an image the upper and lower border) and the second tuple pads the second axis (the left and right borders) with one "0".

You do not want to pad the last dimension, as this is the dimension storing the RGB information.

And as you stated in your question that you want a white border: constant_values should be set to 255 or 1, depending on the range of your image. Using 0 results in a black border.

Whilst I see you already have an answer, I wanted to show the general case where you want to pad with something other than black or white, i.e. you want to add a coloured border. I couldn't get any of the methods suggested in the other answers to do that, so...

Say you have lena.png as follows:

enter image description here

Then you can do:

from PIL import Image, ImageOps                                                                                                
import numpy as np    

# Load the image - you could just as well use OpenCV `imread()`
img = Image.open('lena.png')   

# Pad 20px to all sides with magenta
padded = ImageOps.expand(img, border=20, fill=(255,0,255)) 

# Save to disk
padded.save('result.png')   

enter image description here


Before anyone decides to downvote because the OP asked how to add white borders, please note you can just as easily add white with this method if you use:

padded = ImageOps.expand(img, border=20, fill=(255,255,255)) 

If you are using numpy arrays to manipulate your images, you can convert from numpy array to PIL Image with:

pil_image = Image.fromarray(numpy_array)

and the other way with:

numpy_array = np.array(pil_image)
Related