Python распараллеливание кода для объединения нескольких изображений - PullRequest
1 голос
/ 16 июня 2020

Я новичок в Python и пытаюсь распараллелить программу, которую я каким-то образом собрал из inte rnet. Программа считывает все файлы изображений (обычно несколько серий изображений, таких как abc001, abc002 ... abc015 и xyz001, xyz002 .... xyz015) в указанной папке c, а затем объединяет изображения в указанном диапазоне. В большинстве случаев количество файлов превышает 10000, и в моем последнем случае мне нужно объединить 24000 изображений. Может ли кто-нибудь помочь мне с:

  • Взяв 2 набора изображений из разных каталогов. В настоящее время мне нужно переместить эти изображения в 1 каталог, а затем работать в указанном каталоге.
  • Чтение только указанных файлов. В настоящее время моя программа читает все файлы, сохраняет имена в массиве (я думаю, что это массив. Также может быть каталогом), а затем использует только изображения, необходимые для объединения. Если я укажу диапазон файлов, он по-прежнему будет проверять все файлы в каталоге и займет много времени.
  • Параллельная обработка - Обычно я работаю с 10 КБ файлов, а иногда и больше. Это изображения, сохраненные в результате моделирования жидкости, которое я выполнял в c раз. В настоящее время я сохраняю около 2k файлов одновременно в отдельных папках и запускаю программу, чтобы объединить эти 2000 файлов за один раз. Затем я копирую все выходные файлы в отдельную папку, чтобы хранить их вместе. Было бы здорово, если бы я мог использовать все 16 ядер процессора для объединения всех файлов в 1 go.

Серия изображений 1 такая. Считайте, что это серия фотографий кота, идущего к камере. Каждый кадр имеет суффикс 001,002, ..., n.

Так выглядит серия изображений 1. Считайте, что это серия фотографий, на которых выражение лица кошки меняется с каждым кадром. Каждый кадр имеет суффикс 001,002, ..., n.

Код в настоящее время объединяет каждый кадр из set1 и set2 для предоставления output.png, как показано в ссылке здесь .

import sys
import os
from PIL import Image

keywords=input('Enter initial characters of image series 1    [Ex:Scalar_ , VoF_Scene_]:\n')
keywords2=input('Enter initial characters of image series 2    [Ex:Scalar_ , VoF_Scene_]:\n')

directory = input('Enter correct folder name where images are present   :\n')  # FOLDER WHERE IMAGES ARE LOCATED

result1 = {}  
result2={}

name_count1=0
name_count2=0
for filename in os.listdir(directory):
    if keywords in filename:
        name_count1 +=1
        result1[name_count1] = os.path.join(directory, filename)
    if keywords2 in filename:
        name_count2 +=1
        result2[name_count2] = os.path.join(directory, filename)

num1=input('Enter initial number of series:\n')
num2=input('Enter final number of series:\n')


num1=int(num1)
num2=int(num2)

if name_count1==(num2-num1+1):
    a1=1
    a2=name_count1
elif name_count2==(num2-num1+1):
    a1=1
    a2=name_count2
else:
    a1=num1
    a2=num2+1

for x in range(a1,a2):
    y=format(x,'05')        # '05' signifies number of digits in the series of file name Ex: [Scalar_scene_1_00345.png --> 5 digits], [Temperature_section_2_951.jpg --> 3 digits]. Change accordingly 
    y=str(y)
    for comparison_name1 in result1:
        for comparison_name2 in result2:
            test1=result1[comparison_name1]
            test2=result2[comparison_name2]
            if y in test1 and y in test2:
                a=test1
                b=test2
                test=[a,b]
                images = [Image.open(x) for x in test]
                widths, heights = zip(*(i.size for i in images))
                total_width = sum(widths)
                max_height = max(heights)

                new_im = Image.new('RGB', (total_width, max_height))

                x_offset = 0
                for im in images:
                    new_im.paste(im, (x_offset,0))
                    x_offset += im.size[0]
                    output_name='output'+y+'.png'
                    new_im.save(os.path.join(directory, output_name))

Ответы [ 3 ]

1 голос
/ 17 июня 2020

Я тоже делал Python версию, она не такая быстрая, но, может быть, вам ближе: -)

#!/usr/bin/env python3

import cv2
import numpy as np
from multiprocessing import Pool

def doOne(params):
    """Append the two input images side-by-side to output the third."""
    imA = cv2.imread(params[0], cv2.IMREAD_UNCHANGED)
    imB = cv2.imread(params[1], cv2.IMREAD_UNCHANGED)
    res = np.hstack((imA, imB))
    cv2.imwrite(params[2], res) 


if __name__ == '__main__':

    # Build the list of jobs - each entry is a tuple with 2 input filenames and an output filename
    jobList = []
    for i in range(1000):
       # Horizontally append a-XXXXX.png to b-XXXXX.png to make c-XXXXX.png
       jobList.append( (f'a-{i:05d}.png', f'b-{i:05d}.png', f'c-{i:05d}.png') )

    # Make a pool of processes - 1 per CPU core    
    with Pool() as pool:
        # Map the list of jobs to the pool of processes
        pool.map(doOne, jobList)
1 голос
/ 18 июня 2020

Вы можете сделать это немного быстрее с помощью libvips . Чтобы соединить два изображения слева направо, введите:

vips join left.png out.png result.png horizontal

Чтобы проверить, я сделал 200 пар PNG 1200x800 следующим образом:

for i in {1..200}; do cp x.png left$i.png; cp x.png right$i.png; done 

Затем попробовал тест:

time parallel vips join left{}.png right{}.png result{}.png horizontal ::: {1..200}
real    0m42.662s
user    2m35.983s
sys 0m6.446s

С помощью imagemagick на том же ноутбуке я вижу:

time parallel convert left{}.png right{}.png +append result{}.png ::: {1..200}
real    0m55.088s
user    3m24.556s
sys 0m6.400s
0 голосов
/ 16 июня 2020

Вы можете сделать это намного быстрее без Python и использования многопроцессорной обработки с ImageMagick или libvips .

Первая часть - это все настройки:

Сделайте 20 изображений, называемых a-000.png ... a-019.png, которые go от красного к синему:

convert -size 64x64 xc:red xc:blue -morph 18 a-%03d.png

enter image description here

Сделайте 20 изображений, называемых b-000.png ... b-019.png, которые go от желтого до пурпурного:

convert -size 64x64 xc:yellow xc:magenta -morph 18 b-%03d.png

enter image description here

Сейчас добавьте их рядом в c-000.png ... c-019.png

for ((f=0;f<20;f++))
do
    z=$(printf "%03d" $f)
    convert a-${z}.png b-${z}.png +append c-${z}.png
done

Эти изображения выглядят так:

enter image description here

Если все в порядке, вы можете выполнить их все параллельно с помощью GNU Parallel :

parallel convert a-{}.png b-{}.png +append c-{}.png ::: {1..19} 

Benchmark

Я провел быстрый тест и сделал 20 000 изображений a-00000.png ... a-019999.png и еще 20 000 изображений b-00000.png ... b-019999.png с каждым изображением размером 1200x800 пикселей. Затем я выполнил следующую команду, чтобы добавить каждую пару по горизонтали и записать 20000 выходных изображений c-00000.png ... c-019999.png:

seq -f "%05g" 0 19999 | parallel --eta convert a-{}.png b-{}.png +append c-{}.png

, и это занимает 16 минут на моем MacBook Pro со всеми 12 ядрами ЦП. на 100% во всем. Обратите внимание, что вы можете:

  • добавить разделители между изображениями,
  • написать аннотацию к изображениям,
  • добавить границы,
  • изменить размер

если вы используете sh и выполняете много других операций - это всего лишь простой пример.

Обратите внимание, что вы можете получить еще более быстрое время - в районе 10-12 минут, если вы принимаете JPEG вместо PNG в качестве формата вывода.

...