Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I efficently pad an RGB numpy array with the median of the image?

I have RGB images which have already been rescaled so that the longer edge becomes 256 pixels, now I want to pad the border with the median RGB values of that image so the resulting image is always 256x256 pixels.

This code already works, but I am sure there could be a simpler more elegant way to do this:

img = loadAndFitImage(filePath, maxSideLength=256, upscale=True)
shp = img.shape
#the shp in this case is typically (256,123,3) or (99,256,3)

leftPad = (256 - shp[0]) / 2
rightPad = 256 - shp[0] - leftPad
topPad = (256 - shp[1]) / 2
bottomPad = 256 - shp[1] - topPad

# this part looks like there might be a way to do it with one median call instead of 3:
median = (np.median(img[:, :, 0]),np.median(img[:, :, 1]),np.median(img[:, :, 2]))

img = np.lib.pad(img, ((leftPad,rightPad),(topPad,bottomPad),(0,0)),
 'constant',constant_values=0)

if leftPad > 0:
    img[:leftPad,:,0].fill(median[0])
    img[:leftPad,:,1].fill(median[1])
    img[:leftPad,:,2].fill(median[2])
if rightPad > 0:
    img[-rightPad:,:,0].fill(median[0])
    img[-rightPad:,:,1].fill(median[1])
    img[-rightPad:,:,2].fill(median[2])
if topPad > 0:
    img[:,:topPad,0].fill(median[0])
    img[:,:topPad,1].fill(median[1])
    img[:,:topPad,2].fill(median[2])
if bottomPad > 0:
    img[:,-bottomPad:,0].fill(median[0])
    img[:,-bottomPad:,1].fill(median[1])
    img[:,-bottomPad:,2].fill(median[2])

Edit (Additional Info):

  • This is how the final result should look like:

  • Desired:

  • This is how it should not look like (median per column):

  • Undesired:

like image 931
Quasimondo Avatar asked Jul 26 '15 10:07

Quasimondo


People also ask

How do you represent a RGB image in NumPy?

A single RGB image can be represented using a three-dimensional (3D) NumPy array or a tensor. Since there are three color channels in the RGB image, we need an extra dimension for the color channel. A batch of 3 RGB images can be represented using a four-dimensional (4D) NumPy array or a tensor.

How to get the value of each pixel in a NumPy array?

This function converts the input to an array By using numpy.array () function which takes an image as the argument and converts to NumPy array In order to get the value of each pixel of the NumPy array image, we need to print the retrieved data that got either from asarray () function or array () function.

How to convert an image into a NumPy array in Python?

Python provides many modules and API’s for converting an image into a NumPy array. Let’s discuss a few of them in detail. Using NumPy module. Numpy module in itself provides various methods to do the same. These methods are – Method 1: Using asarray() function. asarray() function is used to

How to read an image and convert it to an array?

You can read an image using the PIL open function, and convert it to an array using the numpy array function. Here, we read the images that were created previously, and print their NumPy shape:


2 Answers

You can do it easily with:

import numpy as np

a = np.asarray([[1,2,3,4,5,6],
     [8,4,5,6,7,7],
     [1,2,3,4,5,6],
     [1,2,3,4,5,6],
     [1,2,3,4,5,6],
     [1,2,3,4,5,6]])

b = a * 3
c = a * 4
d = (a,b,c)

im = np.asarray([np.pad(x, (2,), 'constant', constant_values=(np.median(x) ,)) for x in d])
print im

Output:

[[[ 4  4  4  4  4  4  4  4  4  4]
  [ 4  4  4  4  4  4  4  4  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  8  4  5  6  7  7  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  4  4  4  4  4  4  4  4]
  [ 4  4  4  4  4  4  4  4  4  4]]

 [[12 12 12 12 12 12 12 12 12 12]
  [12 12 12 12 12 12 12 12 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12 24 12 15 18 21 21 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12 12 12 12 12 12 12 12 12]
  [12 12 12 12 12 12 12 12 12 12]]

 [[16 16 16 16 16 16 16 16 16 16]
  [16 16 16 16 16 16 16 16 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16 32 16 20 24 28 28 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16 16 16 16 16 16 16 16 16]
  [16 16 16 16 16 16 16 16 16 16]]]

Or in you particular case:

Original Image

import numpy as np
from PIL import Image

filePath = '/home/george/Desktop/img.jpg'

Img = Image.open(filePath)
img = np.asarray(Img, np.int)
shp = np.shape(img)
img = img.transpose(2,0,1).reshape(3,215,215)

leftPad = round(float((255 - shp[0])) / 2)
rightPad = round(float(255 - shp[0]) - leftPad)
topPad = round(float((255 - shp[1])) / 2)
bottomPad = round(float(255 - shp[1]) - topPad)
pads = ((leftPad,rightPad),(topPad,bottomPad))

img_arr = np.ndarray((3,255,255),np.int)
for i,x in enumerate(img):
    cons = np.int(np.median(x))
    x_p = np.pad(x,pads,
                'constant', 
                 constant_values=cons)
    img_arr[i,:,:] = x_p

im_shp = np.shape(img_arr)
ii = np.uint8(img_arr).transpose(1,2,0)

im = Image.fromarray(np.array( (ii) ))
im.show()
im.save((filePath), "JPEG")

Output:

Median Padded Image

like image 168
Geeocode Avatar answered Sep 29 '22 17:09

Geeocode


I was also struggling on this and figured out an elegant answer:

color = np.median(img, axis=(0,1)) img = np.stack([np.pad(img[:,:,c], pad, mode='constant', constant_values=color[c]) for c in range(3)], axis=2)

like image 38
黄梁华 Avatar answered Sep 29 '22 17:09

黄梁华