#python #image #numpy #python-imaging-library
#python #изображение #numpy #python-imaging-library
Вопрос:
Я пытаюсь объединить список изображений на странице с заданной высотой, чтобы они перемещались сначала вниз по странице, затем поперек, например:
Image1 Image4 Image7
Image2 Image5 Image8
Image3 Image6 Image9
Максимальное количество столбцов равно 3. Проблема в том, что эти изображения передаются динамически, но все они имеют фиксированную ширину, т.Е. Они могут занимать только 1/2/3 столбца, поэтому может произойти что-то подобное:
Image1 Image4-Image4
Image2-Image2-Image2
Image3 Image5 Image6
Кроме того, высота каждого изображения в моем списке является переменной, что означает, что количество строк не задано. Итак, если изображение должно было превышать страницу или перекрывать другое изображение. это также должно быть сохранено на потом. Допускаются пробелы, например:
Image1 Image4
Image2-Image2 Image4
Image2-Image2 Image5
В приведенном выше примере Image3 занял всю страницу или, возможно, ~ 3/4 страницы, что означает, что он не поместится, поэтому он сохраняется для другой новой страницы.
Как я могу добиться такого метода объединения изображений?
Комментарии:
1. Важен ли порядок, в котором они отображаются на странице? Например, могу ли я сначала вывести все изображения шириной в 3 столбца, затем все изображения шириной в 2 столбца, каждое из которых сопровождается изображением в 1 столбец, и, наконец, строки с тремя изображениями шириной в 1 столбец, пока они не закончатся?
2. @MarkSetchell Нет, порядок важен, спасибо :).
3. Итак, почему изображение-3 разрешено после Image5 в вашем последнем примере, пожалуйста?
4. Кроме того, почему изображение-4 предшествует изображению-2 в вашем последнем примере, потому что изображение-2 поместилось бы перед изображением-4 в этой первой строке?
5. Итак, порядок важен, но поскольку изображение 3 было слишком большим, его можно переместить на другую страницу, но если следующее изображение может поместиться, оно может просто заполнить пустой слот, имеет ли это смысл?
Ответ №1:
У вас довольно сложный набор правил. Я думаю, вам, вероятно, нужно будет написать некоторый код, если вы хотите именно такого поведения.
Я пытаюсь избежать выполнения какой-либо реальной работы, поэтому я написал немного на python, чтобы выложить страницы для вас:
#!/usr/bin/python3
import sys
import math
import pyvips
column_width = 256
row_height = 256
background_colour = 255 # you could use eg. [128, 255, 128] as well
# pop enough tiles from the argument to fill a page
def layout(tiles):
# we insert an image (at its top-left), or "x" if a tile is covered by an
# image up and left of itself
page = [[None for x in range(3)] for y in range(3)]
# where we put the next tile
current_x = 0
current_y = 0
# loop to fill page
page_filled = False
while not page_filled:
# used up all the tiles?
if tiles == []:
break
this_tile = tiles[0]
tiles_across = math.ceil(this_tile.width / column_width)
tiles_down = math.ceil(this_tile.height / row_height)
# image too large for page
if tiles_across > 3 or tiles_down > 3:
raise Exception(f"tile too large - {this_tile}")
# loop to find the next free space this tile fits
while True:
# too tall for this column?
if tiles_down > 3 - current_y:
current_y = 0
current_x = 1
# too wide for this row?
if tiles_across > 3 - current_x:
# we've filled the page
page_filled = True
break
# is this set of tiles clear?
all_clear = True
for y in range(tiles_down):
for x in range(tiles_across):
if page[current_y y][current_x x]:
all_clear = False
if all_clear:
break
# try the next slot down
current_y = 1
# did we find a spot?
if not page_filled:
# place the tile here and mark the spaces it covers in the page
for y in range(tiles_down):
for x in range(tiles_across):
page[current_y y][current_x x] = "x"
page[current_y][current_x] = this_tile
tiles.pop(0)
# the page has filled -- draw!
image = pyvips.Image.black(3 * column_width, 3 * row_height)
background_colour
for y in range(3):
for x in range(3):
if isinstance(page[y][x], pyvips.Image):
image = image.insert(page[y][x],
x * column_width, y * row_height)
return image
# a source of tiles .. we just load the command-line arguments
all_tiles = [pyvips.Image.new_from_file(filename, access="sequential")
for filename in sys.argv[1:]]
page_number = 0
while all_tiles != []:
filename = f"page-{page_number}.jpg"
print(f"generating {filename} ...")
page = layout(all_tiles)
page.write_to_file(filename)
page_number = 1
Вы можете запустить его следующим образом:
$ ./layout.py ~/pics/shark.jpg ~/pics/k2.jpg ~/pics/shark.jpg ~/pics/shark.jpg ~/pics/shark.jpg ~/pics/shark.jpg ~/pics/shark.jpg ~/pics/shark.jpg
generating page-0.jpg ...
generating page-1.jpg ...
$
Кажется, это работает для меня и реализует все ваши правила (я думаю). Я использовал pyvips для рендеринга страницы, потому что я знаком с этим, но было бы просто заменить его на что-то другое.
Комментарии:
1. Вау, это потрясающе! Именно то, что я искал, большое вам спасибо!
Ответ №2:
Вы можете заставить ImageMagick размещать изображения вертикально первыми в монтаже с помощью хитрости. Сначала транспонируйте изображения, отредактируйте, затем транспонируйте результат.
convert logo3.jpg lena2.jpg hatching.jpg zelda3.jpg -transpose miff:- |
montage - -geometry 2 2 -tile 2x2 miff:- |
convert - -transpose montage_columns.jpg
Комментарии:
1. Спасибо за ответ! Я скоро попробую это
Ответ №3:
Если вас не волнует порядок изображений в результате или номера сетки, и вы просто хотите, чтобы они наилучшим образом соответствовали заданному размеру вывода, то в ImageMagick есть новая функция для этого. Смотрите ASHLAR:ouput.png в https://imagemagick.org/script/formats.php#pseudo
magick lena.jpg barn.jpg mandril3.jpg monet2.jpg zelda1.jpg redhat.jpg -background black -define ashlar:best-fit=true ASHLAR:x.png[600x400 0 0]
Ответ №4:
Вы можете сделать это в Python как вызов подпроцесса ImageMagick montage следующим образом:
import subprocess
cmd = '/usr/local/bin/montage lena.jpg house.jpg boats3_small.jpg barn.jpg cameraman.jpg mandril3.jpg monet2.jpg zelda1.jpg redhat.jpg -tile 3x3 -geometry 0 0 -gravity north -background black montage.jpg'
subprocess.call(cmd, shell=True)
Комментарии:
1. Фред, я не думаю, что это сработает, если некоторые изображения имеют тройную или двойную ширину. Я думаю, что он всегда будет размещать 3 изображения, тогда как он должен просто размещать изображение тройной ширины самостоятельно. И изображение двойной ширины должно быть сопряжено с одним. Я думаю 😉
2. Спасибо за быстрый ответ! Могут ли изображения передаваться по столбцам, а не по строкам? Я вижу, ты положил lena.jpg -> house.jpg -> boat.jpg , она течет горизонтально, но мне нужно, чтобы она текла вертикально.