Skip to content

Instantly share code, notes, and snippets.

@brikeats
Last active April 5, 2017 15:24
Show Gist options
  • Save brikeats/a9ca380269347ea7d7853f8e12a782fe to your computer and use it in GitHub Desktop.
Save brikeats/a9ca380269347ea7d7853f8e12a782fe to your computer and use it in GitHub Desktop.
Partition a big image into equally-size overlapping tiles. Reassemble the tiles.
import numpy as np
from collections import OrderedDict
# im_fn = 'images/copperopolis_quarry_google_17_cropped.tif'
# im = plt.imread(im_fn)
def tile_image(im, tile_size, overlap=0):
"""
Partition a large image into equally-sized overlapping tiles.
Args:
im (array): image with spatial dimensions first.
tile_size (length-2 tuple): desired size of tiles
overlap (int): the amount the tiles overlap.
Returns:
OrderDict with tiles as values. The dict's keys are
(row_sta, col_sta, row_crop, col_crop) and are used
for reassembly.
# FIXME: explain the key-tuples
"""
if tile_size[0] <= 2*overlap or tile_size[1] <= 2*overlap:
raise ValueError('Overlap must be less than half the tile size.')
num_chans = im.shape[2]
num_tile_rows = int(np.ceil(float(im.shape[0]) / (tile_size[0]-2*overlap)))
num_tile_cols = int(np.ceil(float(im.shape[1]) / (tile_size[1]-2*overlap)))
num_rows = num_tile_rows * (tile_size[0]-2*overlap) + 2*overlap
num_cols = num_tile_cols * (tile_size[1]-2*overlap) + 2*overlap
# zero pad exactly 'overlap' above and to left; pad below/to right as need
# to fit an integer number of tiles
padded_im = np.zeros((num_rows, num_cols, num_chans), dtype=im.dtype)
padded_im[overlap:(overlap+im.shape[0]), overlap:(overlap+im.shape[1]), :] = im
tile_dict = OrderedDict()
for row in range(num_tile_rows):
row_sta = row * (tile_size[0] - 2*overlap)
row_end = row_sta + tile_size[0]
for col in range(num_tile_cols):
col_sta = col * (tile_size[1] - 2*overlap)
col_end = col_sta + tile_size[1]
col_crop = max([col_end - im.shape[1] - overlap, 0])
row_crop = max([row_end - im.shape[0] - overlap, 0])
tile = padded_im[row_sta:row_end, col_sta:col_end,...]
tile_dict[(row_sta, col_sta, row_crop, col_crop)] = tile
return tile_dict
def assemble_tiles(tile_dict):
"""
Crop and assemble image tiles into a big mosaic image.
Args:
tile_dict (dict): A dict as produced by `tile_image`. Keys are
(row_sta, col_sta, row_crop, col_crop) and values are arrays
with 3 dimensions -- (channels, height, width)
Returns:
array. The tiles assembled into a big image. Output is of shape
(channels, big_im_height, big_im_width).
"""
tile = tile_dict.values()[0]
tile_sz = tile.shape
print 'tile size', tile_sz
# Figure out the spatial size of the original image
for (row_sta, col_sta, row_crop, col_crop) in tile_dict.keys():
if row_crop:
num_rows = row_sta + tile_sz[1] - row_crop - overlap
if col_crop:
num_cols = col_sta + tile_sz[2] - col_crop - overlap
# Allocate
recon_im = np.zeros((num_rows, num_cols, tile_sz[0]), tile.dtype)
print 'original image size?', recon_im.shape
# Crop the tiles and put them in place
for (row_sta, col_sta, row_crop, col_crop), tile in tile_dict.iteritems():
tile = np.transpose(tile, (1,2,0))
tile = tile[overlap:-overlap, overlap:-overlap, :]
row_end = row_sta + tile.shape[0]
col_end = col_sta + tile.shape[1]
if col_crop:
tile = tile[:,:-col_crop+overlap,:]
if row_crop:
tile = tile[:-row_crop+overlap,:,:]
recon_im[row_sta:row_end, col_sta:col_end] = tile
return recon_im
@joestrummer82
Copy link

i tried the new version again, you have changes something. but it didn't work. can you give me a demo how to execute it, first slice it into image and afterwards assemble it together to get the original input image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment