Difference between revisions of "ImageMagick"

From Noah.org
Jump to navigationJump to search
(14 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
[[Category:Engineering]]
 
[[Category:Engineering]]
 +
[[Category: Imaging]]
  
 
ImageMagick is your friend, but your friend has terrible man pages. The man pages just tell you to go to the web site and read docs in a browser.
 
ImageMagick is your friend, but your friend has terrible man pages. The man pages just tell you to go to the web site and read docs in a browser.
Line 6: Line 7:
  
 
Fred Weinhaus offers [http://www.fmwconcepts.com/imagemagick/ Fred's ImageMagick Scripts]
 
Fred Weinhaus offers [http://www.fmwconcepts.com/imagemagick/ Fred's ImageMagick Scripts]
 +
 +
== Convert a set of images into a single PDF document ==
 +
 +
<pre>
 +
convert page-*.png -adjoin document.pdf
 +
</pre>
  
 
== crop GE ultrasound images to protect anonymity ==
 
== crop GE ultrasound images to protect anonymity ==
Line 35: Line 42:
 
== correct fisheye barrel distortion from an Olloclip fisheye lens for the iPhone 5 ==
 
== correct fisheye barrel distortion from an Olloclip fisheye lens for the iPhone 5 ==
  
 +
This isn't perfect. There is some pincushion remaining and, while lines are straight, nothing meets at a right angle.
 +
 
To just preview the results run this command:
 
To just preview the results run this command:
 
<pre>
 
<pre>
convert fisheye.jpg -distort barrel "0 0 -0.5" - | display -size 1024x768 -
+
convert fisheye.jpg -distort barrel "0 0 -0.5 1.5" - | display -size 1024x768 -
 +
</pre>
 +
 
 +
To save the results in a file then run this command:
 +
<pre>
 +
convert fisheye.jpg -distort barrel "0 0 -0.5 1.5" fish-fixed.jpg
 
</pre>
 
</pre>
  
To make the results permanent then run this command:
+
ImageMagick also has a '''BarrelInverse''' function, which sounds like it should be the opposite of '''barrel''', but ImageMagick seems to generate different results than simply inverting the Z parameter to either function. I prefer the version using '''barrel''' with a negative Z parameter.
 
<pre>
 
<pre>
convert fisheye.jpg -distort barrel "0 0 -0.5" fisheye-fixed.jpg
+
convert fisheye.jpg -distort BarrelInverse "0 0 0.5 0.5" - | display -size 1024x768 -
 
</pre>
 
</pre>
  
Line 78: Line 92:
  
 
See also '''NASA Retinex''' algorithm. Fred has a version that comes close, [http://www.fmwconcepts.com/imagemagick/retinex/index.php retinex].
 
See also '''NASA Retinex''' algorithm. Fred has a version that comes close, [http://www.fmwconcepts.com/imagemagick/retinex/index.php retinex].
 +
 +
== clean up photo of text documents for conversion to PDF, etc. ==
 +
 +
This will convert a photo taken by a mobile phone of a printed page into something suitable for conversion to PDF. Note that this assumes black and white pages. The colorspace will be converted to grayscale with level normalization to flatten to an almost pure black and white image. Note that you may need to adjust the '''40%,60%''' parameter below, which represents two cutoffs, white and black.
 +
<pre>
 +
for fn in *.JPG; do
 +
    mogrify -auto-orient d-grayscale rec601luma -despeckle -normalize -level 40%,60% "${fn}"
 +
done
 +
</pre>
 +
 +
To then convert all the pages to PDF use the following command  (only use '''-rotate 90''' if '''-auto-orient''' didn't work in the previous step).:
 +
<pre>
 +
convert *.JPG -rotate 90 -adjoin document.pdf
 +
</pre>
  
 
== crop ==
 
== crop ==
Line 91: Line 119:
 
# Method 1: simple.
 
# Method 1: simple.
 
convert entropy.ppm -fft +depth +adjoin entropy-%d.png
 
convert entropy.ppm -fft +depth +adjoin entropy-%d.png
# Method 2: quivalent, but with names specified for magnitude and phase images.
+
# Method 2: equivalent, but with names specified for magnitude and phase images.
 
convert entropy.ppm -fft +depth \( -clone 0 -write entropy-magnitude.png +delete \) \( -clone 1 -write entropy-phase.png +delete \) null:
 
convert entropy.ppm -fft +depth \( -clone 0 -write entropy-magnitude.png +delete \) \( -clone 1 -write entropy-phase.png +delete \) null:
 
# Invert the FFT to get the original spatial image.
 
# Invert the FFT to get the original spatial image.
 
convert entropy-magnitude.png entropy-phase.png -ift entropy-spatial.png
 
convert entropy-magnitude.png entropy-phase.png -ift entropy-spatial.png
# Convert the magitude image to something easier to see.
+
# Convert the magnitude image to something easier to see.
 
convert entropy-magnitude.png -auto-level -evaluate log 10000 entropy-spectrum.png
 
convert entropy-magnitude.png -auto-level -evaluate log 10000 entropy-spectrum.png
 
</pre>
 
</pre>
 +
 
== Add text to an image ==
 
== Add text to an image ==
  
Line 126: Line 155:
 
=== example ===  
 
=== example ===  
  
I took a short video using my iPhone4. I then converted the video to individual frames. I applied the '''Median''' filter to remove most moving distractions. Note that a few people in the background remained because they were not moving very much. Note the blue blob in the left third of the image. This was due to a woman walking across the frame and then into the background. In certain parts of the frame the woman's blue pants were on longer than the backgound, so the blue "outvoted" the other pixels.
+
I took a short video using my iPhone4. I then converted the video to individual frames. I applied the '''Median''' filter to remove most moving distractions. Note that a few people in the background remained because they were not moving very much. Note the blue blob in the left third of the image. This was due to a woman walking across the frame and then into the background. In certain parts of the frame the woman's blue pants were on longer than the background, so the blue "outvoted" the other pixels.
 +
<pre>
 +
mplayer -nosound -vo png median_source.mo
 +
convert -evaluate-sequence Median 000*.png median_still.png
 +
</pre>
  
 
[[Image:median_source.mov|frameless]]
 
[[Image:median_source.mov|frameless]]
Line 134: Line 167:
 
<video>median_source.mov</video>
 
<video>median_source.mov</video>
  
[[File:median_source.mov]]
+
[[http://www.noah.org/mediawiki/images/d/d3/median_source.mov mediam_source.mov]]
 +
f
  
 
== Find differences in images ==
 
== Find differences in images ==
Line 168: Line 202:
 
</pre>
 
</pre>
  
If you run without the two options, '''colorspace gray -type grayscale''', then you will end up with 8-bit PNG files that may look right, but they may behave oddly in some applications. In particular, they will annoying `mplayer` and `mencoder` and cause an annoying flicker when you try to convert them to a video format. The problem is that the '''first''' image `mogrify` converts will be in class '''8-bit PseudoClass 256c''', but all subsequent images will be in class '''8-bit DirectClass 129KiB'''. You can see this if you run '''identify *.png'''... I have no idea what is the difference between '''PseudoClass''' and '''DirectClass'''.
+
If you run without the two options, '''colorspace gray -type grayscale''', then you will end up with 8-bit PNG files that may look right, but they may behave oddly in some applications. In particular, they will confuse `mplayer` and `mencoder` and cause an annoying flicker when you try to convert them to a video format. The problem is that the '''first''' image `mogrify` converts will be in class '''8-bit PseudoClass 256c''', but all subsequent images will be in class '''8-bit DirectClass 129KiB'''. You can see this if you run '''identify *.png'''... I have no idea what is the difference between '''PseudoClass''' and '''DirectClass'''.
  
 
== Convert a TIFF image stack into individual images ==
 
== Convert a TIFF image stack into individual images ==
Line 232: Line 266:
  
 
<pre>
 
<pre>
for filename in *.png ; do convert -quality 85 $filename `basename $filename .png`.jpg; done
+
for filename in *.png ; do convert -quality 85 "${filename}" `basename "${filename .png}"`.jpg; done
 
</pre>
 
</pre>
 +
Unless you want to change the filename format and the output format at the same time. The following takes all PNG files with a file name in the pattern of '''view-pid-1716-*.png''' and converts to high quality jpeg, and changes the file names to the pattern '''v*.jpg'''.
 +
<pre>
 +
for fn in *.png; do
 +
    nfn="${fn#view-pid1716-}"
 +
    nfn="${nfn%.*}.jpg"
 +
    convert -quality 95 "${fn}" "v${nfn}"
 +
done
 +
<pre>
  
 
== Resize all images in a directory ==
 
== Resize all images in a directory ==

Revision as of 12:58, 28 August 2017


ImageMagick is your friend, but your friend has terrible man pages. The man pages just tell you to go to the web site and read docs in a browser.

See also

Fred Weinhaus offers Fred's ImageMagick Scripts

Convert a set of images into a single PDF document

convert page-*.png -adjoin document.pdf

crop GE ultrasound images to protect anonymity

Video from a GE ultrasound imaging system comes out at 640x480. The 2D and 3D/4D image data will always appear in a rectangle 528x396 offset by 34x58 from the top-left corner. All other parts of a frame will contain text and data. If you don't need this data, and you wish to ensure patient anonymity, then you can use ImageMagick to crop the video frames. The resulting frames will be 528x396, which is a nearly perfect 4:3 aspect ratio.

mogrify -crop 528x396+34+58 +repage *.png

rotate and crop

By default the rotate operation will expand the final image dimensions to account for the corners that rotate out of the edges of the original image. The following will rotate and image and crop the final image so that it cuts off the corners that fall outside of the original dimensions.

In this example I take an image and rotate it -112 degrees so that the object is aligned horizontally. Note that the corners are cropped and the empty diagonal areas and filled with a black background.

convert rotate_and_crop_112.png  \( +clone -background black -rotate -112 \) -gravity center -compose Src -composite rotate_and_crop_0.png

rotate and crop 112.png --> rotate and crop 0.png

correct barrel distortion from a GoPro Hero

This command corrects for the fisheye, or barrel distortion, the GoPro lens adds to a video. This does not completely remove the barrel distortion. Trying to completely remove it either results in a large portion of the edges getting cropped, or it results in a weird perspective distortion that is almost as bad as the barrel distortion. I find these settings to be a decent compromise. Adjust the -0.3 value to tune the correction.

mplayer -nosound -vo png GOPR0001.MP4
mogrify -distort barrel "0 0 -0.3" *.png

correct fisheye barrel distortion from an Olloclip fisheye lens for the iPhone 5

This isn't perfect. There is some pincushion remaining and, while lines are straight, nothing meets at a right angle.

To just preview the results run this command:

convert fisheye.jpg -distort barrel "0 0 -0.5 1.5" - | display -size 1024x768 -

To save the results in a file then run this command:

convert fisheye.jpg -distort barrel "0 0 -0.5 1.5" fish-fixed.jpg

ImageMagick also has a BarrelInverse function, which sounds like it should be the opposite of barrel, but ImageMagick seems to generate different results than simply inverting the Z parameter to either function. I prefer the version using barrel with a negative Z parameter.

convert fisheye.jpg -distort BarrelInverse "0 0 0.5 0.5" - | display -size 1024x768 -

split MPO stereo 3D images into component stereo pairs

Fujifilm and the Nintendo 3DS uses this format. It's basically a standard JPEG with the main image data holding the right image, and the EXIF MP Image 2 holding the left image. Note that some cameras tag the image as MP Image 3, so you may have to play with the options in the exiftool command.

Note that EXIF thumbnail images vs. EXIF preview images are different concepts. EXIF preview images can be larger than the main image. Some cameras may use the EXIF preview image.

You will need the perl exiftool to perform the following steps. First, install exiftool.

aptitude -q -y install libimage-exiftool-perl
# keep only the main image as the right (strip preview image).
exiftool -trailer:all= input.mpo -o right.jpg
# note that exiftool will mangle the left.jpg name with the input.mpo.
# So don't actually run the command this way because exiftool is weird...
# exiftool -b -mpimage2 -w left.jpg input.mpo
# Instead, run the command like this so that you can actually name the file the way you want.
exiftool -b -mpimage2 input.mpo > left.jpg
# Now use ImageMagick's 'composite' to create a stereo 3D anaglyph.
composite -stereo left.jpg right.jpg stereo_3d.jpg

clean up an image

I always get the -equalize, -auto-level, and -normalize options mixed up. The -normalize option is the one I usually want. Some other options to consider are -sharpen 10x1 and -sigmoidal-contrast 2x50

This usually works pretty well.

convert -despeckle -normalize noisy.png clean.png

See also NASA Retinex algorithm. Fred has a version that comes close, retinex.

clean up photo of text documents for conversion to PDF, etc.

This will convert a photo taken by a mobile phone of a printed page into something suitable for conversion to PDF. Note that this assumes black and white pages. The colorspace will be converted to grayscale with level normalization to flatten to an almost pure black and white image. Note that you may need to adjust the 40%,60% parameter below, which represents two cutoffs, white and black.

for fn in *.JPG; do 
    mogrify -auto-orient d-grayscale rec601luma -despeckle -normalize -level 40%,60% "${fn}" 
done

To then convert all the pages to PDF use the following command (only use -rotate 90 if -auto-orient didn't work in the previous step).:

convert *.JPG -rotate 90 -adjoin document.pdf

crop

This crops a rectangle of 640x480 positioned at 528,90 from an image.

display -crop 640x480+528+90 /var/spool/motion/20121219134800-snapshot.jpg

FFT

# Method 1: simple.
convert entropy.ppm -fft +depth +adjoin entropy-%d.png
# Method 2: equivalent, but with names specified for magnitude and phase images.
convert entropy.ppm -fft +depth \( -clone 0 -write entropy-magnitude.png +delete \) \( -clone 1 -write entropy-phase.png +delete \) null:
# Invert the FFT to get the original spatial image.
convert entropy-magnitude.png entropy-phase.png -ift entropy-spatial.png
# Convert the magnitude image to something easier to see.
convert entropy-magnitude.png -auto-level -evaluate log 10000 entropy-spectrum.png

Add text to an image

This shows how to add caption text to an image using ImageMagick. This is useful for labeling images.

convert -size 360x80 xc:white -font Helvetica -pointsize 64 -draw "text 20,60 'Hello world!'" -geometry +50+50 example.png +swap -composite example-labeled.png

This shows adding text with multiple lines. This is not very elegant, and ImageMagick has other ways to add text that automatically handles multiple lines, but I found this to be the easiest to get working quickly.

convert -size 550x120 xc:white -font Helvetica -pointsize 32 \
-draw "text 10,30 'This shows a close-up of the coins'" \
-draw "text 10,70 'exiting the channel. The first coin'" \
-draw "text 10,110 'will be copper, followed by zinc.'" \
-geometry +50+50 example.png +swap -composite \
example-labeled.png

blend an image stack while removing differences (median filter)

If you take a number of pictures of the same scene you can create a single image that removes the differences between each image. In other words, you can preserve only the common elements. This is useful for removing people or cars moving in front of a background. After this transformation you will have only the parts of the image that didn't move. This is also useful for removing noise from an image stack. You find this in images taken in low light conditions (shot noise) or where you might experience radiation noise (x-ray/gamma noise). If you take multiple identical images in noisy conditions then the median filter can be used to blend the image stack into a single, noise-free image.

convert -evaluate-sequence Median stack*.jpg output.jpg

The median filter is similar to averaging an image stack (--evaluate-sequence Mean), but averaging will give a blurry image similar to what you would get with a long exposure. The median filter is good for situations where you want to eliminate differences between images. The mean filter will keep differences. Also consider using the Min and Max operations with --evaluate-sequence.

example

I took a short video using my iPhone4. I then converted the video to individual frames. I applied the Median filter to remove most moving distractions. Note that a few people in the background remained because they were not moving very much. Note the blue blob in the left third of the image. This was due to a woman walking across the frame and then into the background. In certain parts of the frame the woman's blue pants were on longer than the background, so the blue "outvoted" the other pixels.

mplayer -nosound -vo png median_source.mo
convert -evaluate-sequence Median 000*.png median_still.png

File:median source.mov

median still.png

<video>median_source.mov</video>

[mediam_source.mov] f

Find differences in images

quick hack to finding differences in images

This is useful to search for unusual pictures in a large set of images that are mostly the same.

In this example, I'm expecting a relatively bright blue object to appear in some images of a set that are otherwise nearly identical. I was searching a long video stream for a blue scintillation flash triggered by an x-ray emitter. This creates a log file showing the average blue value for each frame of the video. After the log is generated you simply look for the frames that have a much higher average than surrounding frames.

for fn in *.png; do 
    echo -n "${fn} : "
    convert ${fn} -colorspace rgb -scale 1x1 -format "%[fx:floor(100*b)]" info:
done | tee -a blue_average.log

Create an animated gif with a 'patrol cycle'

Create an animation with a sequence of frames forward and then backward. Actually, this example creates them backward then forward. This is called a patrol cycle after the back-and-forth march that a guard walks.

The delay parameter is in 1/100th of a second. A value of '3' would be about 33 frames a second.

convert seq-*.png -set delay 10 -reverse \
    seq-*.png -set delay 10 \
    -loop 0 animation.gif

Convert 16-bit grayscale PPM or TIFF images to 8-bit PNG

The correct way (or at least the best way) to convert 16-bit grayscale TIFF or PPM file to PNG is to use the following command:

mogrify -colorspace gray -type grayscale -depth 8 -format png ct-scan-frames-*.ppm

If you run without the two options, colorspace gray -type grayscale, then you will end up with 8-bit PNG files that may look right, but they may behave oddly in some applications. In particular, they will confuse `mplayer` and `mencoder` and cause an annoying flicker when you try to convert them to a video format. The problem is that the first image `mogrify` converts will be in class 8-bit PseudoClass 256c, but all subsequent images will be in class 8-bit DirectClass 129KiB. You can see this if you run identify *.png... I have no idea what is the difference between PseudoClass and DirectClass.

Convert a TIFF image stack into individual images

Tiff image stacks are often used in scientific visualization and medical imaging. It's basically a way to store multiple images in a single file. It's kind of like a GIF animation. Sometimes you see the phrase "multi-page images" or "multi-image sequence". Formats like JPEG and PNG do not support image stacks.

You might also want to see the -adjoin and +adjoin command-line options.

The simplest way is to specify an output filename with a C-style integer format string. This will automatically enable the +adjoin feature (the opposite of -adjoin). The following is an example using a C-style format %02d to number a sequence of PNG images converted from a TIFF image stack:

convert ct_scan_brain_abby_normal.tif ct_scan_stack_%02d.png

Contact Sheet / Thumbnail sheet

Where 'images_*.png' may be a filename glob pattern or a list of filenames.

montage -label '%f' images_*.png contact-sheet.png

You cannot directly set the size of the montage sheet, but you can modify the size of thumbnails and the spacing between them.

montage *.png  -geometry 200x200+4+4 -depth 8 thumbnails.png

Convert an image to an icon

This creates an 80x80 icon. If an edge needs to be cropped then it tries to do the right thing. This first does a resize to force an image to at most 80x80; then this does an extent which sets the page to exactly 80x80. If one or more edges are smaller than 80x80 then the image it padded on the borders to fill exactly the given extent.

convert input.jpg -resize 80x80^ -gravity center -extent 80x80 icon.png

Resize with stretching

You have to be sure to specify the ! or ^ modifiers in the resize geometry if you want the image to actually stretch to fit the new geometry. Otherwise, ImageMagick will try to preserve the aspect ratio by only adjusting one of the dimensions, or by filling with a given color.

In this example each image is 570x36, but I want to make them 10 times taller by stretching the image vertically.

mogrify -resize 570x360! radon-row-*.png

See ImageMagick Resize.

Convert all images in a directory from one format to another

This is easy. Use Mogrify, not Convert. The following example converts all PNG files to JPEG:

mogrify -format jpg -quality 85 *.png

I always forget this. Maybe it's because the ImageMagick docs say:

Mogrify overwrites the original image file, whereas, 
convert writes to a different image file.

Which is true unless you want to convert a group of images. In that case, you use Mogrify instead of Convert. Why? I would call this a bug. If you try this with Convert it will not work (and will, in fact, destroy the last image in your directory).

It beats doing it this way:

for filename in *.png ; do convert -quality 85 "${filename}" `basename "${filename .png}"`.jpg; done

Unless you want to change the filename format and the output format at the same time. The following takes all PNG files with a file name in the pattern of view-pid-1716-*.png and converts to high quality jpeg, and changes the file names to the pattern v*.jpg.

for fn in *.png; do 
    nfn="${fn#view-pid1716-}"
    nfn="${nfn%.*}.jpg"
    convert -quality 95 "${fn}" "v${nfn}"
done
<pre>

== Resize all images in a directory ==

This converts all the images in the current directory to JPEG images scaled to fit a 480x272 screen. This is the resolution of the PSP. Sometimes it's just easier to use `find` rather than try to think the way ImageMagick thinks.
<pre>
find . -exec convert {} -format jpg -quality 80 -resize 480x272^ -gravity center -extent 480x272 ../output/{}.jpg \;

Be careful when resizing and centering an image in a larger field. The -size 1280x720 xc:black option is actually one option. Do not split the xc:black off the -size option. Option order is very critical (and confusing). It's easy to mess this up.

find . -exec convert {} -colorspace gray -type grayscale -depth 8 -resize 1280x720\< -size 1280x720 xc:black +swap -gravity center -composite ../output/{} \;

Remove Transparency

This will turn all transparent pixels in an image to the given background color.

convert input.png -background white -flatten output.png

Display Alpha Transparency over white background

This displays a transparent image without that stupid gray checkerboard pattern which is totally useless for looking at postscript images.

display -background white -flatten image.ps

Working with RAW files (NEF)

Sometimes I have to work with raw image files from a Nikon D2X (saved as NEF file). ImageMagick cannot work directly with raw NEF files. You need to install a few extra tools: netpbm and dcraw.

aptitude install netpbm dcraw

The `dcraw` command converts raw files from various cameras to PBM format. The netpbm commands are used to convert the PBM format to something easier for ImageMagick to deal with.

Convert all NEF images to PNG:

dcraw -c -w input.NEF | pnmtopng > output.png

To convert an entire directory:

for filename in *.NEF ; do dcraw -c -w $filename | pnmtopng > $filename.png ; done

Build ImageMagick from source with FFT and HDRI support

Unfortunately the Ubuntu repositories do not include a version of ImageMagick built with FFT and HDRI support. I use both of these feature, so I need to build from source. identify -list configure

sudo aptitude -q -y install libtiff4-dev libjpeg-dev fftw3 fftw3-dev libltdl-dev
wget http://www.imagemagick.org/download/ImageMagick.tar.bz2
tar xjf ImageMagick.tar.bz2
cd ImageMagick-*
./configure --with-fftw=yes --with-modules=yes --enable-hdri --enable-openmp
make
sudo make install
sudo ldconfig /usr/local/lib

Note that the default Ubuntu configuration of ImageMagick uses the following configure parameters. You may wish to merge some of these into your custom configuration.

./configure  '--prefix=/usr' '--sysconfdir=/etc' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--with-modules' '--with-gs-font-dir=/usr/share/fonts/type1/gsfonts' '--with-magick-plus-plus' '--with-djvu' '--enable-shared' '--without-dps' '--without-fpx' '--with-perl-options=INSTALLDIRS=vendor' '--x-includes=/usr/include/X11' '--x-libraries=/usr/lib/X11' 'CFLAGS=-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security' 'LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro' 'CPPFLAGS=-D_FORTIFY_SOURCE=2' 'CXXFLAGS=-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security'