Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have a folder with images separated into channels:

IMAGE_A_R.jpg
IMAGE_A_G.jpg
IMAGE_A_B.jpg
IMAGE_A_RGB.jpg
IMAGE_A1_R.jpg
IMAGE_A1_G.jpg
IMAGE_A1_B.jpg
IMAGE_A1_RGB.jpg
IMAGE_B_R.jpg
IMAGE_B_G.jpg
IMAGE_B_B.jpg
IMAGE_B_RGB.jpg

What I'm doing now is making 4x1 pictures using montage and naming then "OUTPUT_%d.jpg". This however forces me to manually rename them into e.g. "IMAGE_A.jpg" afterwards, which for this large image collection is very time consuming.

What I'd like to do is to automatically, from the list above create 4x1 montages named:

IMAGE_A.jpg
IMAGE_A1.jpg
IMAGE_B.jpg

Ideally, I'd like to automatically combine all "IMAGE_A" into a 4x montage, all "IMAGE_B" into another and so on. Each IMAGE_[letter] can have from 1-4 numbers so it's not possible to simply make for example a 4x2 montage.

I've tried using %[name] and %f with no luck and haven't found anything helpful in the ImageMagick manual or in my google searches.

I suspect that to do this I'd have to use some BASH-script, but I fear I have to little knowledge to do that without help.

Thanks in advance for any help!

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

First, collect the list of image names:

ls *jpg | gawk -F_ '{print $2}' | sort | uniq

Now, pass them through montage:

ls *jpg | gawk -F_ '{print $2}' | sort | uniq | 
 while read n; do montage *\_$n\_* IMAGE_$n.jpg; done

This assumes your file names contain no spaces or other strange characters. I'm not sure about your "ideal" case. If you update you question to show your "ideal" output, I should be able to work something out for you.


Update:

This I wrote a tiny Perl script should do what you need:

#!/usr/bin/env perl

my %k;             ## declare the hash that will store the image names
while(<>){         ## loop through STDIN
    chomp;         ## remove newline (\n)
    @a=split(/_/); ## split the line on '_' and save as array @a

    ###################################################
    # Since the image names can have varying numbers  #
    # of "_", we want to use the penultimate item in  #
    # the array ($a[$#a-1]) as the image name prefix  #
    ###################################################
    $a[$#a-1]=~s/\d*//g;

    #############################################################
    # Now that we have the prefix ('A' or 'B' in your example), #
    # we will save this image name in the hash of that prefix   #
    #############################################################
    $k{$a[$#a-1]}{$_}=1;
}
## The keys of the hash '%k' are all the prefixes we have found
foreach my $prefix (keys(%k)){
    @images=keys(%{$k{$prefix}});   ## all the images with this prefix

    ## Print the montage command to be executed (testing)
    print "montage @images -title $prefix -tile 4x $prefix.jpg\n";

    ##############################################################
    # If the commands printed above are correct, uncomment this  #
    # line to execute them instead of only printing.             #
    ##############################################################
    #`montage @images -title $prefix -tile 4x $prefix.jpg`
}

You can either save it as foo.pl or whatever you prefer and run it like this:

ls *jpg | perl foo.pl

Or you can run it as a one liner:

ls *jpg | perl -e 'my %k; while(<>){chomp; @a=split(/_/); $a[$#a-1]=~s/\d*//g; $k{$a[$#a-1]}{$_}=1;} foreach my $prefix (keys(%k)){@images=keys(%{$k{$prefix}}); `montage @images -title $prefix -tile 4x $prefix.jpg`;}'

IMPORTANT: This script is very simple and will not work if your file names contain spaces or other strange characters. I am assuming that this is not a problem for you, it is relatively easy to fix but makes the syntax more complex all around.

share|improve this answer
    
Thanks a lot, that's awesome. –  Morgan Mar 12 '13 at 8:11
    
The ideal case would be: Files are named [name]-[letter][number]-[channel].jpg, where [number] isn't present on all images (the letter-only image being an overview). Ideally all images with the same [name] and [letter] should be in the same montage, each image labeled with [channel], the montage having a header being [name] and the file named [name]-[letter].jpg –  Morgan Mar 12 '13 at 8:20
    
From what I can see, the command you posted only looks at the [letter][number] ending. Since are the same for all [name], that will not work perfectly. If needed, I could easily change the naming of the files to so that all have [number]. –  Morgan Mar 12 '13 at 8:32
    
Thanks to your script above, with slight modifications, I managed to almost do what I want: ls *jpg | gawk -F_ '{print $1}' | sort | uniq | while read n; do montage $n\_* -title $n -tile 4x $n.jpg; done; However, I can't figure out how to separate them based on only the letter (see above). Nor can I figure out how to fetch the channel name. Now, this is of lesser importance - and while I'd love to know how to do this - you've already helped me enough. Thanks! –  Morgan Mar 12 '13 at 13:54
    
@Morgan you're very welcome, I am still not entirely clear on what you want. Could you give a detailed example? Do you want all A, A1, A2 etc images in the same file? Some simple scripting should be able to do what you need. Also, the ls *jpg in your previous comment is useless if you are also doing ls *HeLa*. –  terdon Mar 12 '13 at 13:57
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.