0

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 Answers2

0

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)

manaclan
  • 816
  • 9
  • 20
  • Its a start thank you, however this code also cuts out the data from each row, I want to slice the tiles within each row and then reposition them out a bit from one another – 77two4seven4 Nov 26 '21 at 14:31
  • @77two4seven4 you're wanting an 8x9 tiles so in large image they'd be very similar to squares, also if you want to not losing data then I will change my answer arcordingly – manaclan Nov 26 '21 at 14:33
  • @77two4seven4 check my update. I copy each tile and paste it to a bigger image – manaclan Nov 26 '21 at 14:49
  • I appreciate your help, I think there is a miss understanding. I'm not looking to cut out a part of the image out around each rectangle. I'm looking to slice the image up into rectangles and then space them out apart so that the output image would be wider. and then in between each row I am looking to remove some of the image – 77two4seven4 Nov 26 '21 at 15:31
  • humh, I believe my code does slice the image without losing data then space them to make output image wider. Check the images's shape at the end of my answer – manaclan Nov 27 '21 at 01:42
  • check my **Update1** code for remove the tiles. Also at the end of my answer there is images shape that demonstate I'm slicing the image and space them so the output image is actually bigger – manaclan Nov 27 '21 at 02:17
  • Im getting two errors, NameError: name 'np' is not defined and AttributeError: 'tuple' object has no attribute 'full' – 77two4seven4 Nov 27 '21 at 14:14
  • ah, i forgot: `pip install numpy` and in the code `import numpy as np` – manaclan Nov 27 '21 at 14:15
  • the other error is AttributeError: 'tuple' object has no attribute 'full' I appriciate the help – 77two4seven4 Nov 27 '21 at 14:32
  • give me the line of code that causing the error. Also, there is only one 'full' in my code so I think you must be assigned `np` some where in the code you are using. Check to see whether there are other `np` other than the `np` in `import numpy as np` – manaclan Nov 27 '21 at 14:35
  • new_img = np.full((image.shape[0] + num_y*padding_y, image.shape[1] + num_x*padding_x,3),255) AttributeError: 'tuple' object has no attribute 'full' – 77two4seven4 Nov 27 '21 at 14:46
  • are there any line of code that contains `np`? – manaclan Nov 27 '21 at 14:54
  • line 13 in your example – 77two4seven4 Nov 27 '21 at 14:58
  • can you paste the code you're using to execute the program somewhere then send me the link? – manaclan Nov 27 '21 at 15:00
  • https://ufile.io/6wm910iy – 77two4seven4 Nov 27 '21 at 15:09
  • I saw line #6 in your code there is `np = ()` remove it then run again – manaclan Nov 27 '21 at 15:10
  • glad you find it helpful :) – manaclan Nov 27 '21 at 15:36
0

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.

aretor
  • 2,379
  • 2
  • 22
  • 38