1

From an image made up of 9 smaller images arranged as a 3x3-grid like

AAA
BBB
CCC

i want to automatically generate all possible variations as .pngs, where the position of the smaller images does matter, no position can be empty and and each small image must be present three times. I managed to get a list of these permutations with python:

from sympy.utilities.iterables import multiset_permutations
from pprint import pprint
pprint(list(multiset_permutations(['A','A','A','B','B','B','C','C','C'])))

resulting in 1680 variations:

[['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'],
 ['A', 'A', 'A', 'B', 'B', 'C', 'B', 'C', 'C'],
 ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'B', 'C'],
 ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'C', 'B'],
 ['A', 'A', 'A', 'B', 'C', 'B', 'B', 'C', 'C'],
 ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C'],
...
 ['C', 'C', 'C', 'B', 'B', 'B', 'A', 'A', 'A']]

How can i replace each letter for each line with the respective small images A.png, B.png and C.png, which are all square 1000 x 1000 px, with the first three 1000 px apart, and two more rows below? Thank you for your help!

mfg
  • 35
  • 4
  • Not sure I understand. What is A.png? B.png? Are they 1x1 pixel images? – Mark Setchell Sep 18 '21 at 20:18
  • What do you mean by *"elements"* please? – Mark Setchell Sep 18 '21 at 20:22
  • A.png is an image 1000 x 1000 px showing Person A, B.png is a same-siced image of Person B, and C.png the same size of Person C. By "Elements" i meant those three images, they are arranged in a 3x3 grid (so each face is there 3 times). – mfg Sep 18 '21 at 20:29
  • You don't expose all permutation rules, neither tell what is this pseudo 2d array you write here. Please edit your question and clarify the rules for the arrangement. – Léa Gris Sep 18 '21 at 20:38
  • My list is basically showing the positions of the images from top left to bottom right, so in pixels this would be ['0 0', '1000 0', '2000 0', '0 1000', '1000 1000', '2000 1000', '0 2000', '1000 2000', '2000 2000'] – mfg Sep 18 '21 at 20:38
  • If I permute ABC with ABC with ABC there will be 27 permutations. If I permute ABCABCABC with ABCABCABC with ABCABCABC there will be 972 permutations. If I permute ABC with ABC with ABC with ABC with ABC with ABC with ABC with ABC with ABC there will be 19,683 permutations. How do you get 1680 please? – Mark Setchell Sep 18 '21 at 21:20
  • @MarkSetchell Given that elements of permutations are identical, there are only 1680 unique permutations. – xenoid Sep 18 '21 at 21:45

2 Answers2

2

If you have three independent images (each in its own file), then is just matter of generating the unique permutations and using

montage -geometry +0+0 A.png B.png C.png B.png C.png A.png C.png A.png B.png ABCBCACAB.png

(actually, you don't even need to generate the 1680 unique ones if the output file is named after the permutation, but doing so will save on I/O...)

xenoid
  • 8,396
  • 3
  • 23
  • 49
  • Thank you! This worked for me while i am not sure i did exactly what you suggested with the link to the unique permutations. – mfg Sep 19 '21 at 21:59
2

As you seem happy enough to use Python to generate the permutations, I added in the ImageMagick stuff via the subprocesses module, but that is sequential so I added multiprocessing.

It is still pretty inefficient because you are spawning 1680 subprocesses that each load ImageMagick and each read 9 images. I think you'd probably want to load your 3 images into Python just once and generate your montages in Python... but that's not what you asked! Questions, and answers are free on StackOverflow, so you could, of course, ask that question too.

import subprocess
from multiprocessing import Pool
from sympy.utilities.iterables import multiset_permutations

def GenerateOne(f):
    cmd = ['montage', '-geometry', '+0+0']
    for z in f:
        cmd.append(f'{z}.png')
    filename = ''.join(f) + '.png'
    cmd.append(filename)
    # DEBUG print(' '.join(cmd))
    subprocess.run(cmd)

if __name__ == '__main__':
    # Create a pool of processes
    p = Pool()

    # Create a list of montages to create
    perms = multiset_permutations(['A','A','A','B','B','B','C','C','C'])
 
    Map the list onto the Pool
    p.map(GenerateOne, perms)

That actually produces commands like this, which you can see by uncommenting the DEBUG line:

montage -geometry +0+0 C.png C.png C.png B.png B.png A.png A.png B.png A.png CCCBBAABA.png
montage -geometry +0+0 C.png C.png C.png B.png B.png A.png B.png A.png A.png CCCBBABAA.png
montage -geometry +0+0 C.png C.png C.png B.png B.png B.png A.png A.png A.png CCCBBBAAA.png
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432