У меня есть изображение с размерами высота / ширина 3837x5126 пикселей соответственно.
Моя цель - разделить это изображение на отдельные плитки с точными размерами 1000x1000 пикселей. Если изображение нельзя разделить равномерно, необходимо создать перекрывающиеся фрагменты, чтобы все фрагменты размером 1000x1000 пикселей.
Вот визуализация ROUGH , созданная в PowerPoint для иллюстрации того, что я пытаюсь сделать:
Мой мыслительный процесс был таким:
- разделите изображение на мой идеальный размер (1000)
- обратите внимание на остаток
- создайте смещение путем деления этого остатка на все деления
- для каждого деления, вычтите смещение
- перекрывающиеся плитки создаются с размерами 1000x1000.
Вот код, который у меня есть.
import numpy as np
def get_divisions(num, divisor):
n = num / divisor
divisions = math.floor(n)
remainder = n % 1
offset = remainder / divisions
return divisions, offset
def get_tiles(height, width, window_size=1000):
number_of_rows, row_offset = get_divisions(height, window_size)
number_of_columns, col_offet = get_divisions(width, window_size)
tiles = []
for row in range(number_of_rows):
for col in range(number_of_columns):
if row == 0:
row_offset = 0
if col == 0:
col_offset = 0
x = (col * window_size) - (col_offset * window_size)
y = (row * window_size) - (row_offset * window_size)
w = window_size
h = window_size
tiles.append([x, y, h, w])
return np.array(tiles, dtype="uint32")
height = 3837
width = 5126
get_tiles(height, width)
выводит:
array([[ 0, 0, 1000, 1000],
[1000, 0, 1000, 1000],
[2000, 0, 1000, 1000],
[3000, 0, 1000, 1000],
[4000, 0, 1000, 1000],
[ 0, 1000, 1000, 1000],
[1000, 1000, 1000, 1000],
[2000, 1000, 1000, 1000],
[3000, 1000, 1000, 1000],
[4000, 1000, 1000, 1000],
[ 0, 2000, 1000, 1000],
[1000, 2000, 1000, 1000],
[2000, 2000, 1000, 1000],
[3000, 2000, 1000, 1000],
[4000, 2000, 1000, 1000]], dtype=uint32)
Как видите, моя матрица[x, y, h, w]
неверно, потому что есть некоторые точки x, y, которые находятся за пределами изображения 3837x5126 пикселей.
Любая помощь будет принята с благодарностью!
Редактировать:
Вот ответ @HansHirse дал с некоторыми добавленными тестами.
import unittest
import math
import numpy as np
def tile(h, w, tile_width=None, tile_height=None, window_size=100):
np.seterr(divide='ignore', invalid='ignore')
if not tile_width:
tile_width = window_size
if not tile_height:
tile_height = window_size
wTile = tile_width
hTile = tile_height
if tile_width > w or tile_height > h:
raise ValueError("tile dimensions cannot be larger than origin dimensions")
# Number of tiles
nTilesX = np.uint8(np.ceil(w / wTile))
nTilesY = np.uint8(np.ceil(h / hTile))
# Total remainders
remainderX = nTilesX * wTile - w
remainderY = nTilesY * hTile - h
# Set up remainders per tile
remaindersX = np.ones((nTilesX-1, 1)) * np.uint16(np.floor(remainderX / (nTilesX-1)))
remaindersY = np.ones((nTilesY-1, 1)) * np.uint16(np.floor(remainderY / (nTilesY-1)))
remaindersX[0:np.remainder(remainderX, np.uint16(nTilesX-1))] += 1
remaindersY[0:np.remainder(remainderY, np.uint16(nTilesY-1))] += 1
# Initialize array of tile boxes
tiles = np.zeros((nTilesX * nTilesY, 4), np.uint16)
k = 0
x = 0
for i in range(nTilesX):
y = 0
for j in range(nTilesY):
tiles[k, :] = (x, y, hTile, wTile)
k += 1
if j < (nTilesY-1):
y = y + hTile - remaindersY[j]
if i < (nTilesX-1):
x = x + wTile - remaindersX[i]
return tiles
class TestTilingWithoutRemainders(unittest.TestCase):
def test_it_returns_tiles_without_overflow(self):
self.assertEqual(tile(500, 500, window_size=500).tolist(), np.array([[0, 0, 500, 500]], dtype="uint16").tolist())
self.assertEqual(tile(250, 500, window_size=250).tolist(), np.array(
[[0, 0, 250, 250], [250, 0, 250, 250]], dtype="uint16"
).tolist())
self.assertEqual(tile(500, 250, window_size=250).tolist(), np.array(
[[0, 0, 250, 250], [0, 250, 250, 250]], dtype="uint16"
).tolist())
class TestTilingWithRemainders(unittest.TestCase):
def test_it_returns_tiles_with_overflow(self):
self.assertEqual(tile(500, 501, window_size=500).tolist(), np.array(
[[0, 0, 500, 500], [1, 0, 500, 500]], dtype="uint16"
).tolist())
self.assertEqual(tile(251, 250, window_size=250).tolist(), np.array(
[[0, 0, 250, 250], [0, 1, 250, 250]], dtype="uint16"
).tolist())
class TestTilingWithInvalidWindowSizes(unittest.TestCase):
def test_it_raises_an_error_with_invalid_tile_height(self):
self.assertRaises(ValueError, tile, 500, 500, tile_height=50000000)
def test_it_raises_an_error_with_invalid_tile_width(self):
self.assertRaises(ValueError, tile, 500, 500, tile_width=50000000)
def test_it_raises_an_error_with_invalid_window_size(self):
self.assertRaises(ValueError, tile, 500, 500, window_size=50000000)