In the end, I wrote a small function that scales the image using scipy.ndimage.zoom , but to reduce the scale, it first expands it to be a multiple of the original form, and then reduces the scale by averaging over the block. It accepts any other keyword arguments for scipy.zoom ( order and prefilter )
I'm still looking for a cleaner solution using the available packages.
def zoomArray(inArray, finalShape, sameSum=False, **zoomKwargs): inArray = np.asarray(inArray, dtype = np.double) inShape = inArray.shape assert len(inShape) == len(finalShape) mults = [] for i in range(len(inShape)): if finalShape[i] < inShape[i]: mults.append(int(np.ceil(inShape[i]/finalShape[i]))) else: mults.append(1) tempShape = tuple([i * j for i,j in zip(finalShape, mults)]) zoomMultipliers = np.array(tempShape) / np.array(inShape) + 0.0000001 rescaled = zoom(inArray, zoomMultipliers, **zoomKwargs) for ind, mult in enumerate(mults): if mult != 1: sh = list(rescaled.shape) assert sh[ind] % mult == 0 newshape = sh[:ind] + [sh[ind] / mult, mult] + sh[ind+1:] rescaled.shape = newshape rescaled = np.mean(rescaled, axis = ind+1) assert rescaled.shape == finalShape if sameSum: extraSize = np.prod(finalShape) / np.prod(inShape) rescaled /= extraSize return rescaled
source share