Last active
April 5, 2017 15:24
-
-
Save brikeats/a9ca380269347ea7d7853f8e12a782fe to your computer and use it in GitHub Desktop.
Partition a big image into equally-size overlapping tiles. Reassemble the tiles.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.