Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scipy.ndimage.zoom result depends on image size

I noticed that the result of scipy.ndimage.zoom depends on the size of the original image. In the following code sample a checkerboard image is generated and then zoomed with ndimage.zoom. If one checkerboard tile is just 2x2 pixels, the zoom factor seems to be too large and the resulting image gets cropped. In contrast, if the tile has dimensions 10x10, the result looks good.

from __future__ import division

import numpy as np
from scipy import ndimage, misc
import wx

y,x = 2,2   # change tile size here
imgdata = np.zeros((y,x),dtype='uint8')
imgdata[y/2:,x/2:] = 255
imgdata[:y/2,:x/2] = 255
imgdata = np.tile(imgdata,(4,4))
imgdata = np.array((imgdata,imgdata,imgdata))
d,y,x = imgdata.shape

zoom = 200.0/y

w, h = int(x*zoom), int(y*zoom)

app = wx.App(None)

zoomed = np.ascontiguousarray(ndimage.interpolation.zoom(imgdata,[1,zoom, zoom],order=0).transpose((1,2,0)), dtype='uint8')
image = wx.ImageFromBuffer(w, h, zoomed)
image.SaveFile('zoomed.png',wx.BITMAP_TYPE_PNG)

02x02 tile: 2x2 tile

10x10 tile: 10x10 tile

Up to know I have been using scipy.misc.imresize which does not show this behaviour but I want to avoid the additional dependency on PIL.

Am I doing something wrong or is this a bug in zoom?

like image 700
Christian K. Avatar asked Oct 19 '22 22:10

Christian K.


1 Answers

i'ts been a while since you posted your question... in case you're still interested, I had a similar problem and used the following:

import skimage
data_new = skimage.transform.resize(data_old, [new_shape_x, new_shape_z], order = 0)

Make sure you set order = 0, because the default is order = 1, which will result in a first order spline interpolation between the values (this causes the tiles to blur at their boundaries).

Anyway, I don't know if that's a good way to do it, it worked for me though. I can't answer if it's a bug, because I really don't know enough about programming to answer that. Furthermore I also tried to use the the scipy.ndimage.interpolation.zoom function, but then the boundaries of the tiles weren't where they should be, like in your case. Therefore I used skimage.

In case you're interested in the context: I worked on fracture-mechanics and needed to create random strength-distributions that are varying smoothly. So I created a surface with a combination of sinus and cosinus funcitons, that had a certain number of periods in x and z direction. Then I took the absolute value of that surface and multiplied it with an irregular chessboard-like surface. The numbers of tiles in each direction on the chessboard-like surface had to match the number of periods/2 in the corresponding strength-variation surface. The final surface was calculated as follows (piecewise addition and multiplication):

strength_surface[i,j] = strength_mean[i,j] + random_grid[i,j] * strength_variation[i,j]

where random_grid had to be resized to match the shape of the other surfaces.

like image 52
ricecracker Avatar answered Oct 21 '22 14:10

ricecracker