I'm trying to use this dataset to do Exposure Meging (Fusion) in Python. Each image in the dataset has an OpenEXR file that can be downloaded (i don't have much experience with this file format).
I want to extract different samples (jpg or png) from the OpenEXR file with different exposures .
I managed to do that in Darktable :
Open the OpenEXR file (image)
Change the Exposure
Save as jpg
redo for each exposure value (-3EV, -2EV, -1EV, 0EV, 1EV, 2EV, 3EV).
The problem : I have 100 images and i want to automate this process. any idea on how to do that ?
Thank you in advance
Since each increment of EV ("Exposure Value") corresponds to doubling the exposure, and EXR files are in linear light (not gamma-encoded), you would expect that you can double the pixel values in an EXR file to add 1EV and halve them to do -1EV...
So, I downloaded the Luxo EXR file from here. Then I went into Photoshop and clicked:
Image -> Mode -> 8-bits/channel
and selected Method = Exposure and Gamma and set exposure=+1 and saved the resulting file as a JPEG with +1 in its name. I repeated that for EV-3, EV-2, EV+0, EV+1, EV+2, EV+3.
I then looked at the resulting files with ImageMagick using commands like the following in the Terminal to examine the mean value of the combined RGB image:
magick identify -verbose image-EV+2.jpg
I then went about producing those same mean values, and found that the following works:
# To increase 1 EV
magick input.exr -evaluate multiply 2 result.jpg
# To increase 2 EV
magick input.exr -evaluate multiply 4 result.jpg
# To increase 3 EV
magick input.exr -evaluate multiply 8 result.jpg
And so on...
So, I wrote a bash script to do that as follows, which you could save in your HOME directory as adjust.sh:
#!/bin/bash
# Default file, if none specified
file=${1:-/Users/mark/Desktop/LuxoDoubleChecker.exr}
# Default EV of +1, if none specified
EV=${2:-1}
# Strip extension
base="${file%.*}"
# Apply given EV to file and save with new name
new="${base}EV${EV}.jpg"
echo "Applying EV $EV to $file, saving as $new"
magick "$file" -evaluate multiply $(bc -l <<< "2^$EV") "$new"
Then, just necessary once, make it executable:
chmod +x $HOME/adjust.sh
And then you run it like this to add +3EV to SomeImage.exr:
~/adjust.sh SomeImage.exr 3
Sample Output
Applying EV 3 to SomeImage.exr, saving as SomeImageEV3.jpg
Alternatively, if you save this script as allEVs.sh, it will load the specified image just once and generate all 7 exposures in one go without re-reading the input EXR file 7 times:
#!/bin/bash
# Default file, if none specified
file=${1:-/Users/mark/Desktop/LuxoDoubleChecker.exr}
# Strip extension to get base without extension
base="${file%.*}"
magick "$file" \
\( +clone -evaluate multiply 0.125 -write "${base}EV-3.jpg" +delete \) \
\( +clone -evaluate multiply 0.25 -write "${base}EV-2.jpg" +delete \) \
\( +clone -evaluate multiply 0.5 -write "${base}EV-1.jpg" +delete \) \
\( +clone -evaluate multiply 1 -write "${base}EV-0.jpg" +delete \) \
\( +clone -evaluate multiply 2 -write "${base}EV+1.jpg" +delete \) \
\( +clone -evaluate multiply 4 -write "${base}EV+2.jpg" +delete \) \
-evaluate multiply 8 "${base}EV+3.jpg"
Please check carefully that this works correctly for you before basing a lifetime's analysis on it...
Keywords: Image processing, HDR, High Dynamic Range, EXR, EV, Exposure Value, f-stop, stop, stops, exposure, increase, decrease, tone map, ImageMagick.
Related
i have a folder of images with names foo<bar>.png where <bar> ranges from 0 to 100.
When i create a gif of these images with
convert -dispose previous -delay 10 -resize 25% -loop 0 *.png myimage.gif
it creates a gif with images in order like 0,1,2,3...
Is there a command to select images in random order?
If your PNG images are all the same dimensions, and if the number of images can be evenly divided into a grid, like 72 images would make a grid of 8 x 9 images, and if your images are small enough to read them all into a single ImageMagick command, here is a command that will randomize the order of a group of 72 input images...
convert *.png -virtual-pixel tile +append -crop 9x1# -append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 8x9# +repage -set delay 10 -loop 0 image.gif
It basically makes a grid, randomly rolls all the rows, then randomly rolls all the columns. The shuffle scatters the images pretty well, but if you want a deeper shuffle, copy and paste those two "-crop ... -distort" lines, and add them below the first two...
convert *.png -virtual-pixel tile +append -crop 9x1# -append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 8x9# +repage -set delay 10 -loop 0 image.gif
Carefully replace the "8"s and "9"s with the width and height of the grid that holds the number of images you're using. I use it in a script that shuffles a deck of playing card images, 13 rows and 4 columns.
This uses ImageMagick v6 in Windows CMD syntax. In a BAT script double all the percent signs "%%". It would probably work on a *nix OS by changing all the continued-line carets "^" to backslashes "\". For ImageMagick v7 use "magick" instead of "convert".
I can tell you 2/3 of the answer on Windows, and hopefully some other kind soul can add the rest for you. Nobody said answers have to be complete.
Create a text file containing the names of the PNGs you want to animate. I believe that is:
DIR /B *.png > filelist.txt
Shuffle the lines in that file. I don't know how to do that in Windows. In Linux and macOS it is shuf. Here's a little Python equivalent:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," filelist.txt > shuffled.txt
Pass that file to ImageMagick like this:
convert -loop 0 -delay 80 #filelist.txt animation.gif
If you get that working, you can avoid the need for a temporary file by using this syntax:
DIR /B *.png | SHUFFLELINES | convert -loop 0 -delay 80 #- animation.gif
I have a set of images, and I can use the Imagemagick montage command on them to produce a montage image file with transparent background (let's call this fgimg). Now I have another existing image (let's call this bgimg) that I'd like to use (after some special processing with the convert command) as the background for fgimg, which can be achieved within the same convert command. At this point it seems trivial to avoid writing the temporary fgimg to disk, simply by piping the standard output of montage to the standard input of convert.
My problem is that the special processing I'm applying to bgimg will require some knowledge of the image properties of fgimg (e.g., resizing bgimg to have the same size as fgimg), which I don't know in advance. How can this information be retrieved and used in the convert command?
Note: I'm using Imagemagick version 6.9.7-4 on Linux.
I'll include some commands below to further illustrate the problem in detail.
The following command produces the montage image fgimg from a set of input images. The output is in the 'special' miff format (which seems best for temporary output to be worked on later), and has transparent background so that the actual background can be applied later. Most of the other options here are not important, but the point is that the output size (dimensions) cannot be determined in advance.
montage input_*.jpg -tile 5x -border 2 -geometry '200x200>+20+20' \
-gravity center -set label '%f\n%G' -background none -fill white \
-title 'Sample Title' miff:fgimg
Next, I have another input image bgimg.jpg. I want to perform some processing on it before using it as background to fgimg. The processing can be quite complex in general, but in this example, I want to:
resize bgimg.jpg to fit inside the dimensions of fgimg without any cropping;
apply a fade-to-black effect around the edges;
make it the same size as fgimg, with a black background;
combine this with fgimg to produce the final output.
Notice that I need the size of fgimg in two places. I can first extract this into a shell variable:
size=$(identify -format '%G' miff:fgimg)
Then I can do all the steps above in one convert command (note that $size is used twice):
convert "bgimg.jpg[$size]" -gravity center \
\( +clone -fill white -colorize 100% -bordercolor black \
-shave 20 -border 20 -blur 0x20 \) -compose multiply -composite \
-background black -compose copy -extent $size \
miff:fgimg -compose over -composite final_out.jpg
Now here is the problem: I want to avoid writing the temporary file fgimg to disk.
I could replace miff:fgimg with miff:- in both the montage and convert commands and then just pipe one to the other: montage ... | convert .... But how do I deal with the $size?
I tried to use file descriptors (miff:fd:3) but this does not seem to work, which is confirmed by the comments to this question.
Is there a way to do this (in Imagemagick v6) without creating a temporary file?
This example command uses ImageMagick v6 on a bash shell. Instead of "montage" it starts by using "convert" to create a "logo:", one of IM's built-in sample images, then pipes it out as a MIFF and into the "convert" command that follows. You can pipe the output of "montage" just as easily. And it uses another IM built-in image "rose:" as your "bgimg.jpg"...
convert logo: miff:- | convert - rose: \
+distort SRT "%[fx:t?min(u.w/v.w,u.h/v.h):1] 0" \
-shave 1 +repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap -composite final_out.jpg
That reads the piped image "-" and the background image "rose:".
Then it uses "+distort" with an FX expression to scale "rose:" to the maximum dimensions that still fit within the original piped input image. That operation adds a pixel all around so we use "-shave 1" to get rid of that.
Next inside parentheses it clones that re-scaled background image, makes an edge blur mask, and composites them to make the fade-to-black edge on the background image. Right after the parentheses it deletes the non-edged background image.
In the next parentheses it clones the input image, makes it black, clones the modified background image, and composites it centered over the black one. Again the non-extended background image is discarded after the parentheses with "-delete 1".
Finally the modified background and the input image are put in the proper order with "+swap" and composited for the final output. Run this command without the last "-composite" to see the two images that result from the prior parts of the command.
Both the main input image and background image can be any size, any dimensions, and any aspect ratio. This works for me on v6.8.9 on a bash shell. It should work on any ImageMagick newer. It should work on Windows by removing all the backslashes that escape parentheses and changing the continued-line backslashes "\" to carets "^".
EDITED TO ADD:
You can use that FX expression to find the scaling amount, save it as a variable, then isolate the background image inside parentheses and use that variable to do the scaling and shaving there. That way it only affects the background image. There may be a rounding error with that, but the main image, which determines the exact final output dimensions, will be unaffected. Note the difference in the first few lines of this command...
convert logo: miff:- | convert - rose: \
-set option:v1 "%[fx:min(u.w/v.w,u.h/v.h)]" \
\( -clone 1 +distort SRT "%[v1] 0" -shave 1 \) -delete 1 \
+repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap final_out.jpg
I have the following image:
What I want is to preserve only red color and desaturate
every other color into grayscale. Resulting in this:
How can I do that with Imagemagick command line?
I tried this but failed:
convert original.png \( -clone 0 -transparent red -alpha extract -transparent black \) redonly.png
Here is one way, though not perfect, using ImageMagick. I specify hue=0 deg for red and tolerance=25 deg both in range 0 to 360.
Input:
hue=0
tolerance=25
toler=`convert xc: -format "%[fx:(100*$tolerance/360)]" info:`
hueval=`convert xc: -format "%[fx:50-$hue]" info:`
thresh=`convert xc: -format "%[fx:100-$tolerance]" info:`
convert tomato.jpg \
\( -clone 0 -colorspace gray -colorspace sRGB \) \
\( -clone 0 -colorspace HSL -channel 0 -separate +channel \
-evaluate AddModulus ${hueval}% \
-solarize 50% -level 0x50% \
-threshold $thresh% \) \
-swap 0,1 -alpha off -compose over -composite \
result.jpg
Also not perfect, but fairly easy to understand. Basically, you could use the fx operator to inspect the Hue of each pixel and, depending on its Hue/colour, return either the original pixel or its greyscale equivalent.
So, as a first stab, you might do this to replace all pixels exhibiting a high Hue value with their greyscale (lightness) equivalent:
magick ripe.jpg -fx "(u.hue<0.1)? u : u.lightness" result.jpg
Then you might realise that red Hues wrap around at 0/360 degrees on the Hue circle, so you could do:
magick ripe.jpg -fx "(u.hue<0.1)||(u.hue>0.9)? u : u.lightness" result.jpg
Explanation
There are a couple of things going on here. Firstly, the -fx operator is a very low-level, extremely powerful (and sadly rather slow because it is interpreted) way of running a piece of "code" on every pixel in the image. Secondly, I am running a ternary operator with the format:
condition? valueA : valueB
so I am testing a condition for every pixel, and if true I return valueA, and if false I return valueB. When I refer to u and u.hue and u.lightness, the u means the first image in my command - I could load two images and use features of the first to select features of the second, then I would use u and v to differentiate. Finally, the values are scaled on the range [0,1] so I don't test for "Hue>350 in the range [0,360]", instead I test for Hue>0.9 as a sloppy equivalent - I guess I could have used Hue>(350/360). Note that you can make the expression arbitrarily complicated and also put it in a separate file to re-use it like this:
magick ripe.jpg -fx #DeSatNonRed.fx result.jpg
DeSatNonRed.fx might look something like this:
hueMin=350/360;
hueMax=20/360;
(hue>hueMin) || (hue<hueMax) ? u : u.lightness
Note that, in the general case, you should also really consider Saturation when looking at Hues, which you can add in above, but which I omitted for clarity, and because your image is almost fully saturated anyway.
Keywords: Image processing, ImageMagick, low-level fx operator, ternary, pixel-by-pixel, evaluate, expression.
I know exactly what I want to do, and could do it with python, scipy, and PIL.
I want to use imagemagick, since it is designed specifically for these actions.
T is highest legal intensity (0, of course is lowest)
Input image into temporary MPC named I
Gaussian blur I and store into temporary MPC named G
Subtract and divide D = (I - G) / G
Get maximum M = max (T * abs(D))
Offset, normalize, and scale O = T * (D + M) / (2 * M)
Output O into file name output.png
I can't figure out how to do this from the online documentation.
Imagemagick documentation vocabulary seems to be for
image manipulation professionals and it is beyond my understanding.
I have tried to reproduce your commands in Imagemagick, but I am not sure of the result or about whether T and M should be in range 0 to 1 or 0 to Quantumrange (0 to 65535 for Q16 HDRI IM compile). I tested on the Imagemagick logo: image using Imagemagick 7.0.7.21 Q16 HDRI.
T="65000"
sigma=5
magick logo: I.mpc
magick I.mpc -blur 0x$sigma G.mpc
magick I.mpc G.mpc +swap -compose minus -composite G.mpc +swap -compose divide -composite D.mpc
M=`magick D.mpc D.mpc -compose multiply -composite -evaluate pow 0.5 -evaluate multiply $T -format "%[fx:maxima]" info:`
M2=`magick xc: -format "%[fx:2*$M]" info:`
magick D.mpc -evaluate add $M -evaluate divide $M2 -evaluate multiply $T output.png
Line 1: Set T=65000 (range 0 to 65355)
Line 2: Set gaussian blur sigma to 5
Line 3: Read the input into I.mpc
Line 4: Apply gaussian blur to I.mpc to create G.mpc
Line 5: Create D=(I-G)/G (requires HDRI IM 7 compile to keep negative values)
Line 6: Compute M=T*Max(sqrt(D*D)) as a single number variable in the range 0 to 65535 (Quantumrange for 16-bit IM compile)
Line 7: Compute 2*M as variable M2
Line 8: Compute output O = T * (D + M) / (2 * M)
If this is not correct (does not match your python, etc, approach, then please post and input and output example and then I might be able to correct any false assumptions or mistakes and make it work the same.
If wanting to use Imagemagick 6, then one would have to compile or get a version that is Q16 HDRI compiled. Then in the above commands, just change magick to convert.
Here is the corrected method as one long command line using Imagemagick 7.0.7.21 Q16 HDRI.
T="65000"
sigma=5
magick \
\( logo: -write mpr:imgI +delete \) \
\( mpr:imgI -blur 0x$sigma -write mpr:imgG +delete \) \
\( mpr:imgI mpr:imgG +swap -define compose:clamp=off -compose minus -composite mpr:imgG +swap -define compose:clamp=off -compose divide -composite -write mpr:imgD +delete \) \
\( mpr:imgD mpr:imgD -define compose:clamp=off -compose multiply -composite -evaluate pow 0.5 -evaluate multiply $T -write mpr:imgT +delete \) \
mpr:imgT -set option:mm "%[fx:maxima]" -set option:nn "%[fx:2*maxima]" +delete mpr:imgD -evaluate add "%[mm]" -evaluate divide "%[nn]" -evaluate multiply $T output3.png
Here is a bash script for handling
Any 0-255 image file recognized by convert.
I tried it on some sample files of my own.
It works.
#!/bin/bash
echo $#
if [ $# -ne 1 ]
then
echo "Usage: ${0} {imagefilename}"
elif [ -f "$1" ]
then
T="255"
sigma=5
convert ${1} ${1}.I.mpc
convert ${1}.I.mpc -blur 0x$sigma ${1}.G.mpc
convert ${1}.I.mpc ${1}.G.mpc +swap -compose minus -composite ${1}.G.mpc +swap -compose divide -composite ${1}.D.mpc
M=`convert ${1}.D.mpc ${1}.D.mpc -compose multiply -composite -evaluate pow 0.5 -evaluate multiply $T -format "%[fx:maxima]" info:`
M2=`convert xc: -format "%[fx:2*$M]" info:`
convert ${1}.D.mpc -evaluate add $M -evaluate divide $M2 -evaluate multiply $T ${1}.mdif.png
else
echo "Usage: ${0} {imagefilename}\n!exists ${1}"
fi
I had hoped the imagemagick commands would have been
easier to read and easier to understand but fmw42 achieved the goal.
CORRECTION:
I made a mistake in my previous posts. When using HDRI and needing to keep negative values or values outside the range 0 to quantumrange, any composite operations will by default clamp and give results as if HDRI was not enabled. So one needs to add defines before the composite operations to keep from clamping (clipping) to normal non-HDRI dynamic range limits. So the correct code would be as follows:
T="65000"
sigma=5
magick logo: I.mpc
magick I.mpc -blur 0x$sigma G.mpc
magick I.mpc G.mpc +swap -define compose:clamp=off -compose minus -composite G.mpc +swap -define compose:clamp=off -compose divide -composite D.mpc
M=`magick D.mpc D.mpc -define compose:clamp=off -compose multiply -composite -evaluate pow 0.5 -evaluate multiply $T -format "%[fx:maxima]" info:`
M2=`magick xc: -format "%[fx:2*$M]" info:`
magick D.mpc -evaluate add $M -evaluate divide $M2 -evaluate multiply $T output.png
The result is a bit different from my earlier results.
I'm looking to efficiently generate various sized thumbnails with ImageMagick's convert utility in Python. Some of my image files are quite large (~15MB JPGs).
One way I could do it would be to take the full-sized image, and to generate the various thumbnails from the full-sized image, as follows:
convert sample_image.jpg -resize 1024x768 sample_image-1024x768.jpg
convert sample_image.jpg -resize 800x600 sample_image-800x600.jpg
convert sample_image.jpg -resize 400x300 sample_image-400x300.jpg
convert sample_image.jpg -resize 200x150 sample_image-200x150.jpg
But another way would be to resize the images from each other:
convert sample_image.jpg -resize 1024x768 sample_image-1024x768.jpg
convert sample_image-1024x768.jpg -resize 800x600 sample_image-800x600.jpg
convert sample_image-800x600.jpg -resize 400x300 sample_image-400x300.jpg
convert sample_image-400x300.jpg -resize 200x150 sample_image-200x150.jpg
Is there any downside to doing this, or perhaps a better way? It seems like this would be a lot more efficient.
As a corollary, are there any flags or "tricks" convert uses to speed up the process?
ImageMagick has a few tricks up its sleeves which help you to optimize for speed when you want to process large images and when you want to create different output from the same original:
Make use of ImageMagick's mpr:{name} feature, which makes it temporarily save the input image into a named memory program register, from which you can later (while processing) read the data much faster than you could do from harddisk.
Do all resize operations in one single process writing out the different output sizes you require.
And the even better news is you can combine both these into one single command.
So you do not need to run multiple processes with all their context-switching overhead -- do it all in one go.
The following example also crops two separate areas from the original image and creates re-sized thumbnails from them, just to show how many different operations IM can do in one commandline. It also, of course outputs the sizes you requested. (You'll need, of course, a really large-dimensioned input image for the cropping parameters to work).
convert \
huge-original.jpg \
-quality 80 \
-colorspace rgb \
+profile '*' \
-filter Lanczos \
-write mpr:copy-of-huge-original \
+delete \
mpr:copy-of-huge-original -crop '3000x2000+0+480' -resize '200x125!>' -write thumb1-extract.jpg +delete \
mpr:copy-of-huge-original -crop '2000x1500+280+220' -resize '75x75!>' -write thumb2-extract.jpg +delete \
mpr:copy-of-huge-original -resize '1024x768' -write sample-1024x768.jpg +delete \
mpr:copy-of-huge-original -resize '800x600' -write sample-800x600.jpg +delete \
mpr:copy-of-huge-original -resize '400x300' -write sample-400x300.jpg +delete \
mpr:copy-of-huge-original -resize '200x150' -write sample-200x150.jpg +delete \
mpr:copy-of-huge-original -resize '163x163!>' -write sample-163x163.jpg
Update
I only now saw the question asked by #JonathanOng: How to stream the output to <stdout>?
Assuming, you want the format going to stdout also be JPEG, you can try this:
convert \
huge-original.jpg \
-quality 80 \
-colorspace rgb \
+profile '*' \
-filter Lanczos \
+write mpr:copy-of-huge-original \
mpr:copy-of-huge-original -crop '3000x2000+0+480' -resize '200x125!>' +write thumb1-extract.jpg \
mpr:copy-of-huge-original -crop '2000x1500+280+220' -resize '75x75!>' +write thumb2-extract.jpg \
mpr:copy-of-huge-original -resize '1024x768' +write jpeg:- \
mpr:copy-of-huge-original -resize '800x600' +write jpeg:- \
mpr:copy-of-huge-original -resize '400x300' +write jpeg:- \
mpr:copy-of-huge-original -resize '200x150' +write jpeg:- \
mpr:copy-of-huge-original -resize '163x163!>' +write jpeg:-
This way each variant will go to stdout. How you deal with this stream of consecutive images then, is up to you...
Note, instead of writing -write filename +delete you can use +write filename. It amounts to the same effect.
I tried timing vipsthumbnail against #KurtPfeifle's excellent answer. I ran this with a 10k x 10k pixel RGB JPG image (about 15MB):
convert \
/data/john/pics/wtc.jpg \
-quality 80 \
-colorspace rgb \
+profile '*' \
-filter Lanczos \
-write mpr:copy-of-huge-original \
+delete \
mpr:copy-of-huge-original -resize '1024x768' -write sample-1024x768.jpg +delete \
mpr:copy-of-huge-original -resize '800x600' -write sample-800x600.jpg +delete \
mpr:copy-of-huge-original -resize '400x300' -write sample-400x300.jpg +delete \
mpr:copy-of-huge-original -resize '200x150' -write sample-200x150.jpg +delete \
mpr:copy-of-huge-original -resize '163x163!>' -write sample-163x163.jpg x.jpg
I found I needed the extra x.jpg at the end, I'm not sure why. On this machine (E5-1650 3.2 GHz, IM 6.8.9-9) I see:
$ time ./m.sh
real 0m6.560s
user 0m31.908s
sys 0m0.264s
peak RES 711MB
This is (I think) the equivalent with vipsthumbnail:
img=/data/john/pics/wtc.jpg
icc=/usr/share/color/argyll/ref/sRGB.icm
for size in 1024x768 800x600 400x300 200x150 163x163; do
vipsthumbnail $img --size $size --eprofile $icc -o vips-sample-$size.jpg[Q=80]
done
vipsthumbnail defaults to Lanczos3. Timing it with vips-8.4.4 I see:
$ time ./n.sh
real 0m2.376s
user 0m2.412s
sys 0m0.108s
peak RES 70MB
So a useful speedup, and a large drop in memory use.
Because memory use is low, you can run many vipsthumbnail in parallel without killing your server. If I change the script to be:
img=/data/john/pics/wtc.jpg
icc=/usr/share/color/argyll/ref/sRGB.icm
parallel vipsthumbnail $img \
--size {} --eprofile $icc -o vips-sample-{}.jpg[Q=80] ::: \
1024x768 800x600 400x300 200x150 163x163
I now see:
$ time ./n.sh
real 0m0.593s
user 0m1.960s
sys 0m0.100s
peak RES 280MB
More than 10x faster than ImageMagick.
For my point of view, and after testing, resizing 1024x768 to 800x600 is bad for rescaling algorithm.
The next resize are more easier, because of multiple of integer (2).
So, for quality reason, I personnaly thing, this is better :
convert sample_image.jpg -resize 1024x768 sample_image-1024x768.jpg
convert sample_image.jpg -resize 800x600 sample_image-800x600.jpg
convert sample_image-800x600.jpg -resize 400x300 sample_image-400x300.jpg
convert sample_image-400x300.jpg -resize 200x150 sample_image-200x150.jpg
15MB JPGs are really large. I would first resize it to reasonable size (say 2500x2500) with fastest "-sample" parameter and this smaller image then resize to different thumbnails.
You can make intelligent decision based on image size and choose the right way of resize.
I would recommend to focus on thumbnail quality instead of conversion speed so please look at different filters (-filter), sharping (-unsharp) and recommended downsampling methods
I'm thumbnailing ~50MB JPG files. The one option which made the biggest difference (~5x speedup) was "-define jpeg:size 128x128" before the input filename. The example given here:
http://www.imagemagick.org/Usage/formats/#jpg_read
...made a huge difference:
convert -define jpeg:size=128x128 jpeg_large.jpg -thumbnail 64x64 jpeg_thumbnail.jpg
-define jpeg:size allows ImageMagick to read in only as much data as it needs from disk, which greatly reduces load time for very large images.
As the linked page suggests, use a jpeg:size= of twice your final thumbnail size to avoid aliasing.
The -thumbnail option, described here:
http://www.imagemagick.org/Usage/resize/#thumbnail
...samples and strips the image, further speeding up the process.