py Сшивание фотографий миллиона файлов - PullRequest
0 голосов
/ 18 июня 2020

Справочная информация

Я работаю над проектом, в котором я пытаюсь напечатать огромный плакат, я уже нашел типографию, которая готова помочь мне напечатать его, но я должен отправить им данные в одном файле (желательно в формате JPEG), но мой проект состоит из более чем 2 миллионов файлов. Вот где начинается борьба; У меня дома нет большого сервера, который я мог бы использовать, чтобы быстро сшить эти изображения размером 256 на 256 пикселей вместе, у меня есть только скромный i7 и 16 ГБ ОЗУ.

Метод

I Я использую PIL.Image для сшивания изображений (приветствуются любые альтернативы).

Мой код работает для файлов меньшего размера, но мои входные данные - это в общей сложности 13 гигабайт файлов JPEG, разделенных на более чем 2 миллиона файлов.

from PIL import Image

"""
1. create a list with pictures
2. stitch them together vertically

>images are all in the folder D:/tiles/ and named after they'r x and y 
 position: "x_y.jpeg" (e.g.: 2000_642.jpeg)

>vertical lines will be put inside folder D:/output/ and will be named after 
 they'r x-position (in the code variable j) (e.g.: 2000.jpeg)
 
>full poster will be put inside D:/poster.jpeg
"""

def joinVert(j,imagePath):
    # open pictures
    images = [Image.open(x) for x in imagePath]
    # get list with width and height
    widths, heights = zip(*(i.size for i in images))
    # get maximum width and total height to find the size of target image
    max_width = max(widths)
    total_height = sum(heights)
    # create target image
    new_im = Image.new('RGB', (max_width, total_height))
    # y_offset defines the amounts of px to top border -- will increase by 
        # height of last pic
    y_offset = 0
    # iterate trough images and paste them into new image
    for im in images:
      new_im.paste(im, (0,y_offset))
      y_offset += im.size[1]
    # save new picture to output
    tgt='D:/output/'+str(j)+'.jpeg'
    new_im.save(tgt)
    return tgt

def joinHor(path,imagePath):
    # open pictures
    images = [Image.open(x) for x in imagePath]
    # get list with width and height
    widths, heights = zip(*(i.size for i in images))
    # get maximum height and total width to find the size of target image
    max_height = max(heights)
    total_width = sum(widths)
    # create target image
    new_im = Image.new('RGB', (total_width, max_height))
    #x_offset defines the amounts of px to left border -- will increase by 
        # width of last pic
    x_offset = 0
    # iterate trough images and paste them into new image
    for im in images:
      new_im.paste(im, (x_offset,0))
      x_offset += im.size[0]
    # save new picture to path
    new_im.save(path)

# list of paths to output files --> will be stiched together later
targets=[]
for j in range(700,715):
    # create a list with all the pictures in this row
    imagePath = []
    for i in range(700,715):
        imagePath.append("D:/tiles/"+str(j)+"_"+str(i)+".jpeg")
    # join all pictures vertically in the list to one, returns path of outputfile
    targets.append(joinVert(j,imagePath))

joinHor("D:/poster.jpeg",targets)

Проблема

AFAIK PIL.Image помещает все данные в ОЗУ. Мой процессор и оперативная память не подыгрывают мне из-за невероятного объема обрабатываемых данных - как бы вы, ребята, записали в файл изображения, который будет больше, чем ваша оперативная память? Любые идеи приветствуются.

...