How to slice and complie an image into a window effect using Python

1k views Asked by At

I would like to slice up an image in python and paste it back together again as a window.

The tiles measure as 8pixels by 9pixels and each row needs to skip 1 pixel

I would then need to merge the tiles back together again with a 1 pixel padding around each tile to give a windowed effect.

The image is black and white but for the example I have used color to show that the windowed effect would need to have a white background

input example

Desired Output

2

There are 2 answers

17
manaclan On BEST ANSWER

Update: change tiles dimension to bigger for illustration, you can adjust per your need
Use this:

import cv2

image = cv2.imread('test.jpg')

tiles_height = 50
tiles_width = 30
# white padding
padding_x = 10
padding_y = 20

num_y = int(image.shape[0]/tiles_height)
num_x = int(image.shape[1]/tiles_width)
new_img = np.full((image.shape[0] + num_y*padding_y, image.shape[1] + num_x*padding_x,3),255)



for incre_i,i in enumerate(range(0,image.shape[0],tiles_height)):
  for incre_j,j in enumerate(range(0, image.shape[1], tiles_width)):
    new_img[i+incre_i*padding_y:i+tiles_height+incre_i*padding_y
            ,j+incre_j*padding_x:j+tiles_width+incre_j*padding_x,:] = image[i:i+tiles_height,j:j+tiles_width,:]
cv2.imwrite('res.jpg',new_img)
print(image.shape, new_img.shape)

Update 1: Because you want to latter remove tiles, I added code that can help you with that. Now all you have to do is changing variables in tiles config, white padding, tile index to be removed:

import cv2

image = cv2.imread('test.jpg')

# tiles config
tiles_height = 50
tiles_width = 30
# white padding
padding_x = 10
padding_y = 20

# tile index to be removed
remove_indices = [(0,0),(3,6)]


num_y = int(image.shape[0]/tiles_height)
num_x = int(image.shape[1]/tiles_width)
new_img = np.full((image.shape[0] + num_y*padding_y, image.shape[1] + num_x*padding_x,3),255)

for incre_i,i in enumerate(range(0,image.shape[0],tiles_height)):
  for incre_j,j in enumerate(range(0, image.shape[1], tiles_width)):
    if (incre_i,incre_j) in remove_indices:
      new_img[i+incre_i*padding_y:i+tiles_height+incre_i*padding_y
            ,j+incre_j*padding_x:j+tiles_width+incre_j*padding_x,:] = 255
    else:
      new_img[i+incre_i*padding_y:i+tiles_height+incre_i*padding_y
              ,j+incre_j*padding_x:j+tiles_width+incre_j*padding_x,:] = image[i:i+tiles_height,j:j+tiles_width,:]
cv2.imwrite('remove_tiles.jpg',new_img)
print(image.shape, new_img.shape)

test.jpg enter image description here res.jpg enter image description here remove_tiles.jpg enter image description here

print(image.shape, new_img.shape) gives (952, 1429, 3) (1332, 1899, 3)

0
aretor On

You can try with skimage.utils.view_as_windows from the scikit-image package:

from skimage.util import view_as_windows
import matplotlib.pyplot as plt
import numpy as np

img = np.random.rand(90, 90, 1)  # gray-scale image, you can change the channels accordingly
img[8::9,] = 0
tiles = view_as_windows(img, (9, 9, 1), (9, 9, 1)).squeeze(2)  # squeeze out unneded dim
tiles = tiles[:, :, :-1, :, :]  # Remove last row of each tile

# plot the original image
plt.axis("off")
plt.imshow(img.squeeze(2))
plt.show()

# plot the tiles
fig, axes = plt.subplots(10, 10)
for i in range(10):
  for j in range(10):
    axes[i, j].axis("off")
    axes[i, j].imshow(tiles[i, j, ...].squeeze(-1))
plt.show()

Here is the result:

Original

original

Sliced

enter image description here

The torch.Tensor.unfold operator from PyTorch could be an option too.