[Solved, use shell to loop] Loop/Repeat/For in ImageMagick?

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
kedlm
Posts: 3
Joined: 2018-09-17T14:11:42-07:00
Authentication code: 1152

[Solved, use shell to loop] Loop/Repeat/For in ImageMagick?

Post by kedlm »

Linux x64: ImageMagick 6.8.8-1 Q16

I need to read a raw image and split it into 16 pieces.
I need to overlay pieces 1 and 2, 3 and 4, etc. and tweak and label each group.
Then I need to convert everything into 1 final output image.

I wrote a bash script to do it but it runs a bit slow.

The single command below "works", needs no temporary files and is faster than the bash script, but I had to use the clone commands exactly the right number of times and hardcode the section names.

Is there a better way to loop in ImageMagick? Or a better way to do this?

(The real version is bigger and has more than the 8 sections in my example)

annotate="-gravity north -stroke #FFFF -fill white -strokewidth 1 -pointsize 15 -annotate 0"
bright="-brightness-contrast 50x50 -black-threshold 20%"
convert \
-size 512x2048 cmyk:test.raw -set colorspace Gray -separate -average -normalize -crop 512x256 +repage \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 1" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 2" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 3" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 4" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 5" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 6" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 7" \) -delete 0 \
\( -clone 0 -crop 512x128 +repage -compose Plus -composite $bright $annotate "Section 8" \) -delete 0 \
-append output.png
Last edited by kedlm on 2018-09-18T09:37:48-07:00, edited 1 time in total.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Loop/Repeat/For in ImageMagick?

Post by fmw42 »

In Unix, you can do subshell processing to do what you need. That is indicated by the parens above and below the code. You basically do a loop over the previous created MPC file (memory mapped), which is fast reading multiple times, inside the subshell. You save to miff:- and then pipe the result to another convert to do the appending.

Here is a simple example. You can change your -crop as you have it and add your own annotate and bright.

Input:
Image

Code: Select all

num=`convert logo: -crop 4x2@ +repage +write tmp.mpc -format "%n\n" info: | head -n 1`
(
for ((i=0; i<num; i++)); do
echo >&2 "$i"
j=$((i+1))
convert tmp.mpc[$i] -gravity west -pointsize 18 -fill "green1" -font ubuntu -annotate +0+0 "Section $j" miff:- 
done
) | convert - -append logo_result.png
Image
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Loop/Repeat/For in ImageMagick?

Post by snibgo »

I can't see any scope for increasing performance. IM doesn't have a looping construct to simplify the code. For jobs like this, I often write a script that contains a loop and builds the final command or script.

I would add "+repage" after the final "-append" because more recent versions of IM take the canvas size from the size of the first image.

"-annotate" can take metadata escapes shown on http://www.imagemagick.org/script/escape.php , so you can use "Section %p". Hence if you arrange to have a list of images, you can automatically annotate them from zero upwards. Add a dummy image at the start to number yours from one upwards.

You crop the 512x2048 image into 8 pieces, then crop each of those into 2 pieces, and "-compose Plus -composite" each pair. You might instead directly crop the 512x2048 image into 16 pieces. Then you could rearrange the order of the images in the list and insert a dummy "NULL:" image, so you have 17 images: the odd numbers, then NULL:, then the even numbers, Then use "-layers composite" to plus each pair. See http://www.imagemagick.org/script/comma ... php#layers

But this is messy. I suggest writing a script that contains a loop and builds the final command or script.
snibgo's IM pages: im.snibgo.com
kedlm
Posts: 3
Joined: 2018-09-17T14:11:42-07:00
Authentication code: 1152

Re: Loop/Repeat/For in ImageMagick?

Post by kedlm »

Thanks for the quick answers!

@fmw42 that was very informative to learn a new way to handle temporary storage and sub shells
@snibgo I hadn't seen the metadata escapes and I added the last +repage; thanks


After some testing, just creating the long command in a for loop results in the simplest code, fastest run time, and no temporary storage on disk.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Loop/Repeat/For in ImageMagick?

Post by fmw42 »

If you add -scene 1 and use %s rather than %p, then you won't need the extra dummy image at the beginning. For example

Code: Select all

convert lena.jpg barn.jpg monet2.jpg mandril3.jpg -scene 1 -gravity center -pointsize 18 -annotate +0+0 "Number %s" test.gif
Starts with Number 1 rather than Number 0 in the output frames.
kedlm
Posts: 3
Joined: 2018-09-17T14:11:42-07:00
Authentication code: 1152

Re: Loop/Repeat/For in ImageMagick?

Post by kedlm »

Good to know. I actually prefer it to start at 0 for the actual task.
Post Reply