简体   繁体   中英

Better image normalization with numpy

I already achieved the goal described in the title but I was wondering if there was a more efficient (or generally better) way to do it. First of all let me introduce the problem.

I have a set of images of different sizes but with a width/height ratio less than (or equal) 2 (could be anything but let's say 2 for now), I want to normalize each one, meaning I want all of them to have the same size. Specifically I am going to do so like this:

  • Extract the max height above all images
  • Zoom the image so that each image reaches the max height keeping its ratio
  • Add a padding to the right with just white pixels until the image has a width/height ratio of 2

Keep in mind the images are represented as numpy matrices of grey scale values [0,255].

This is how I'm doing it now in Python:

max_height = numpy.max([len(obs) for obs in data if len(obs[0])/len(obs) <= 2])

for obs in data:
    if len(obs[0])/len(obs) <= 2:
        new_img = ndimage.zoom(obs, round(max_height/len(obs), 2), order=3)
        missing_cols = max_height * 2 - len(new_img[0])
        norm_img = []
        for row in new_img:
            norm_img.append(np.pad(row, (0, missing_cols), mode='constant', constant_values=255))
        norm_img = np.resize(norm_img, (max_height, max_height*2))            

There's a note about this code:

  • I'm rounding the zoom ratio because it makes the final height equal to max_height, I'm sure this is not the best approach but it's working (any suggestion is appreciated here). What I'd like to do is to expand the image keeping the ratio until it reaches a height equal to max_height. This is the only solution I found so far and it worked right away, the interpolation works pretty good.

So my final questions are:

Is there a better approach to achieve what explained above (image normalization) ? Do you think I could have done this differently ? Is there a common good practice I'm not following ?

Thanks in advance for your time.

  • Instead of ndimage.zoom you could use scipy.misc.imresize . This function allows you to specify the target size as a tuple, instead of by zoom factor. Thus you won't have to call np.resize later to get the size exactly as desired.

    Note that scipy.misc.imresize calls PIL.Image.resize under the hood, so PIL (or Pillow) is a dependency.

  • Instead of using np.pad in a for-loop , you could allocate space for the desired array, norm_arr , first:

     norm_arr = np.full((max_height, max_width), fill_value=255) 

    and then copy the resized image, new_arr into norm_arr :

     nh, nw = new_arr.shape norm_arr[:nh, :nw] = new_arr 

For example,

from __future__ import division
import numpy as np
from scipy import misc

data = [np.linspace(255, 0, i*10).reshape(i,10)
        for i in range(5, 100, 11)]

max_height = np.max([len(obs) for obs in data if len(obs[0])/len(obs) <= 2])
max_width = 2*max_height
result = []
for obs in data:
    norm_arr = obs
    h, w = obs.shape
    if float(w)/h <= 2:
        scale_factor = max_height/float(h)
        target_size = (max_height, int(round(w*scale_factor)))
        new_arr = misc.imresize(obs, target_size, interp='bicubic')
        norm_arr = np.full((max_height, max_width), fill_value=255)
        # check the shapes
        # print(obs.shape, new_arr.shape, norm_arr.shape)
        nh, nw = new_arr.shape
        norm_arr[:nh, :nw] = new_arr
    result.append(norm_arr)
    # visually check the result
    # misc.toimage(norm_arr).show()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM