How to divide a heightmap into several layers with ImageMagick? - image

Let's say I have got a grayscale heightmap that has colors ranging from A (rather dark) to B (rather white). The map is not normalized, so the lowest value isn't pitch black and the highest one probably also isn't fully white.
Let's also say 0 means black and 1 means white. What I want to do is to divide the image into several seperate images based on height. Every image has a black background.
This would for example mean:
Image 1 contains all the image content between 0 and 0.2, with anything above that being reduced to 0.2.
Image 2 contains everything between 0.2 and 0.4, everything below 0.2 is black.
Image 3 is the same between 0.4 and 0.6, and all this goes up to 1. You get the idea.
Do you know any way to automate this process with ImageMagick?
If not, is there any other way I could do this?
Thanks

If you want to slice the image at different heights, then you can do that using a combination of -black-threshold and -white-threshold using percents rather than fractions in ImageMagick. The following will keep each range of gray levels and make the rest black. Black threshold keeps everything above a value and makes the rest black. White threshold keeps everything below a value and makes the rest white. So after the white threshold, we just change white to black.
Unix syntax for IM 6. If using IM 7, change convert to magick
Input:
(Create a gradient image for demonstration)
convert -size 256x256 gradient: grad.png
convert grad.png -write mpr:grad +delete \
\( mpr:grad -white-threshold 20% -fill black -opaque white +write t1.png \) \
\( mpr:grad -black-threshold 20% -white-threshold 40% -fill black -opaque white +write t2.png \) \
\( mpr:grad -black-threshold 40% -white-threshold 60% -fill black -opaque white +write t3.png \) \
\( mpr:grad -black-threshold 60% -white-threshold 80% -fill black -opaque white +write t4.png \) \
\( mpr:grad -black-threshold 80% +write t5.png \) \
null:
Results:
ADDITION
Based upon your comment, the code should be changed as follows:
convert grad.png -write mpr:grad +delete \
\( mpr:grad -white-threshold 20% -fill "gray(20%)" -opaque white +write t1.png \) \
\( mpr:grad -black-threshold 20% -white-threshold 40% -fill "gray(40%)" -opaque white +write t2.png \) \
\( mpr:grad -black-threshold 40% -white-threshold 60% -fill "gray(60%)" -opaque white +write t3.png \) \
\( mpr:grad -black-threshold 60% -white-threshold 80% -fill "gray(80%)" -opaque white +write t4.png \) \
\( mpr:grad -black-threshold 80% +write t5.png \) \
null:
Results:

Related

imagemagic: stacking of the images using convert and montage

My bash script uses convert of the image magic to stack horizontally two types of the images producing 2xN multi-image chart:
convert \( "${output}/type1*.png" -append \) \( "${output}/type2*.png" -append \) +append -background white -alpha deactivate ${output}/summary.png
how would it be possible to add border of the selected dimensions between stacked images in the manner as I may do via montage -mattecolor $color_id ?
montage \( "${output}/type1*.png" \) \( "${output}/type2*.png" \) -geometry 800x600+1+1 -tile x2 -frame 4 -background white -mattecolor lightgoldenrod2 -mode Frame -bordercolor white ${output}/summary.png
vertical borders between each separate sections of the type1/ type2 and a horizontal border between the both parts joined in the summary:
convert \( "${output}/type1*.png" -bordercolor lightgoldenrod2 -border 0x2 -append \) \( "${output}/type2*.png" -bordercolor lightgoldenrod2 -border 0x2 -append \) -bordercolor lightgoldenrod2 -border 2x0 +append -background white -alpha deactivate ${output}/summary.png

Can ImageMagick generate multiple outputs from one input?

I'm running this from the command line:
magick.exe input.png -shave '1x0' output_%d.png
magick.exe input.png -shave '2x0' output_%d.png
magick.exe input.png -shave '3x0' output_%d.png
magick.exe input.png -shave '4x0' output_%d.png
magick.exe input.png -shave '5x0' output_%d.png
magick.exe input.png -shave '0x1' output_%d.png
magick.exe input.png -shave '0x2' output_%d.png
magick.exe input.png -shave '0x3' output_%d.png
magick.exe input.png -shave '0x4' output_%d.png
magick.exe input.png -shave '0x5' output_%d.png
The first command creates output_0.png but the following commands overwrite the same file. Is there a single command that could generate output_0.png to output_9.png instead?
The ImageMagick documentation says:
Filename References
Optionally, use an embedded formatting character to write a sequential
image list. Suppose our output filename is image-%d.jpg and our image
list includes 3 images. You can expect these images files to be
written:
image-0.jpg
image-1.jpg
image-2.jpg
That's the closest evidence I found it's possible to do what I'm looking for in ImageMagick. It's not clear to me if I need to leverage shell scripting to do this or if ImageMagick provides a command line feature.
With ImageMagick you can run multiple operations on separate instances of the input image in a single command by cloning the input and isolating the operations inside parentheses like this...
magick input.png \
\( -clone 0 -shave '1x0' \) \
\( -clone 0 -shave '2x0' \) \
\( -clone 0 -shave '3x0' \) \
\( -clone 0 -shave '4x0' \) \
\( -clone 0 -shave '5x0' \) \
\( -clone 0 -shave '0x1' \) \
\( -clone 0 -shave '0x2' \) \
\( -clone 0 -shave '0x3' \) \
\( -clone 0 -shave '0x4' \) \
\( -clone 0 -shave '0x5' \) \
-delete 0 output_%02d.png
That will create 10 output images, each with a sequential filename with the number padded to two places, like "output_00.png ... output_10.png".
To convert this to Windows CMD syntax you can remove all the backslashes that escape the parentheses, and replace the continued-line backslashes "\" with carets "^".
EDITED TO ADD: There are many ways to accomplish this task with ImageMagick. Here is another example command that would produce the same results, but it uses FX expressions so it will only work in IMv7. (The above command should work with IMv6 by changing "magick" to "convert".)
magick input.png -duplicate 9 -shave "%[fx:t<5?t+1:0]x%[fx:t>4?t-4:0]" output_%02d.png
This reads the input and duplicates it 9 times, then uses FX expressions as arguments to the -shave operation so it can step through all 10 images, shaving each according to the formula in the FX expression.
As #GeeMack points out, there are many ways of doing this with ImageMagick and I was inspired to try a couple of other methods by his marvellous FX expression - just for fun!
Here's what I was originally proposing:
magick input.png -write MPR:orig \
-shave 1x -write out_1.png \
-shave 1x -write out_2.png \
-shave 1x -write out_3.png \
-shave 1x -write out_4.png \
-shave 1x -write out_5.png \
-delete 0--1 \
MPR:orig \
-shave x1 -write out_6.png \
-shave x1 -write out_7.png \
-shave x1 -write out_8.png \
-shave x1 -write out_9.png \
-shave x1 out_10.png
It loads the input image and saves a copy in an MPR or "Magick Persistent Register" called orig. It then shaves a pixel off left and right sides and writes out_1.png, then shaves a further pixel off left and right sides and saves in out_2.png and continues till left and right are shaved by 5 pixels. It then reloads the original from the MPR and shaves off the top and bottom five times.
With a 1080p image, i.e. 1920x1080, this takes 3.4s and uses 96MB of RAM. By comparison, GeeMack's takes 3.5s on my machine and uses 291MB of RAM.
I then parallelised the creation of the left-right shaving with the top-bottom shaving as follows:
magick input.png \
-shave 1x -write out_1.png \
-shave 1x -write out_2.png \
-shave 1x -write out_3.png \
-shave 1x -write out_4.png \
-shave 1x out_5.png &
magick input.png \
-shave x1 -write out_6.png \
-shave x1 -write out_7.png \
-shave x1 -write out_8.png \
-shave x1 -write out_9.png \
-shave x1 out_10.png &
wait
That takes just 1.97s and peaks at 68MB of RAM.
I think GeeMack's solution is probably simplest and most concise, for most cases, but there may be some mileage in some of the ideas here for some situations, i.e. probably larger images.
In case anyone is interested how to measure the peak RAM usage, I used this:
/usr/bin/time -l ./go
1.97 real 6.01 user 2.48 sys
68354048 maximum resident set size
0 average shared memory size
0 average unshared data size
0 average unshared stack size
10343 page reclaims
0 page faults
0 swaps
...
...

How to create a simple reflection using imagemagick with dynamic image sizing?

I've trying to use imagemagick to create a simple reflection, however the documentation has fixed sizes. I've tried to read in the height and width and use those variables but this doesn't produce a reflection.
Here's the documentation
http://www.imagemagick.org/Usage/advanced/
Here's the sample code
convert pokemon.gif \( +clone -flip \) -append \
-size 100x100 xc:black +swap \
-gravity North -geometry +0+5 -composite reflect_perfect.png
Here's my bash script, with my widths and heights...
#!/bin/bash
infile="framed.png"
ww=`convert $infile -format "%w" info:`
hh=`convert $infile -format "%h" info:`
convert $infile -alpha on \
\( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
-size ${ww}x${hh} xc:black +swap \
-gravity North -geometry +0+5 -composite reflect_alpha.png
My resulting image is exactly the same as the source image.
Here's the exact image I'm using
https://www.dropbox.com/s/l8gtieuqi1yoipm/iPhoneXR-4-categories_framed.png?dl=0
The size for the black background must be larger than twice the height of the input and at least as wide as the input. So I would do the following in Imagemagick
Input:
infile="zelda1.jpg"
ww=`convert $infile -format "%[fx:1.5*w]" info:`
hh=`convert $infile -format "%[fx:2.1*h]" info:`
convert $infile -alpha on \
\( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
-size ${ww}x${hh} xc:black +swap \
-gravity North -geometry +0+5 -composite reflect_alpha.png
But you can try my bash unix Imagemagick shell script, 3Dreflection at http://www.fmwconcepts.com/imagemagick/index.html, if you want more flexibility.
ADDITION:
To answer your question, it does not matter if PNG or JPG. The issue is that you have transparency. If you put a transparent background, then
infile="WPB-wtpC.png"
ww=`convert $infile -format "%[fx:1.5*w]" info:`
hh=`convert $infile -format "%[fx:2.1*h]" info:`
convert $infile \
\( +clone -flip -alpha on -channel A -evaluate multiply .35 +channel +write tmp1.png \) -append +write tmp2.png \
-size ${ww}x${hh} xc:none +swap \
-gravity North -geometry +0+5 -compose over -composite reflect_alpha.png
If you use a black background, then
infile="WPB-wtpC.png"
ww=`convert $infile -format "%[fx:1.5*w]" info:`
hh=`convert $infile -format "%[fx:2.1*h]" info:`
convert $infile \
\( +clone -flip -alpha on -channel A -evaluate multiply .35 +channel +write tmp1.png \) -append +write tmp2.png \
-size ${ww}x${hh} xc:black +swap \
-gravity North -geometry +0+5 -compose over -composite reflect_alpha.png
NOTE: I had a typo in the first zelda image code. I accidentally typed w rather than h in the hh equation, which I have now fixed. That may have messed you up.

Bandpass filter with ImageMagick

I've been using Fiji's FFT bandpass filter with great success, but I'd like to do this in the command line with ImageMagick. I see that ImageMagick has FFT filters and they documentation includes low-pass and high-pass filters, but can I perform a bandpass filter?
The bandpass filter settings from Fiji that seem to work well for me:
(With apologies that my filter and FFT knowledge is... really bad, so maybe this is easily accomplished if I knew what to chain together, etc...)
A band pass filter similar to the low pass one you show in your link would be a white ring on a black background for square images. The inner and outer radii of the ring determine the frequencies that would be passed. In ImageMagick you can do that as follows:
Input:
Create ring image:
convert lena-1.png -fill black -colorize 100 \
-fill white -draw "translate 64,64 circle 0,0 0,50" \
-fill black -draw "translate 64,64 circle 0,0 0,20" \
-alpha off -blur 0x1 \
ring.png
Do FFT processing with stretch to full dynamic range:
convert lena-1.png -fft \
\( -clone 0 ring.png -compose multiply -composite \) \
-swap 0 +delete -ift -auto-level \
lena_bp.png
Alternate processing with gain of 10x:
convert lena-1.png -fft \
\( -clone 0 ring.png -compose multiply -composite \) \
-swap 0 +delete -ift -evaluate multiply 10 \
lena_bp.png
As I do not know what they have coded in ImageJ or Fiji and you showed no output, I can only guess that what might be equivalent would be to have inner and outer radii at 3 and 40 pixels from the center. Also I have added again a gain of 10x in dynamic range to make it more visible:
convert lena-1.png -fill black -colorize 100 \
-fill white -draw "translate 64,64 circle 0,0 0,40" \
-fill black -draw "translate 64,64 circle 0,0 0,3" \
-alpha off -blur 0x1 \
ring.png
convert lena-1.png -fft \
\( -clone 0 ring.png -compose multiply -composite \) \
-swap 0 +delete -ift -evaluate multiply 10 \
lena_bp.png
Note that I blurred the ring slightly to reduce "ringing" artifacts. (See https://en.wikipedia.org/wiki/Ringing_artifacts). Many low pass, high pass and band pass filters have stronger/longer tapering similar to increasing the blur. There are specially designed tapers, such as Butterworth. (see https://en.wikipedia.org/wiki/Butterworth_filter)
I have an expanded version of the FFT documentation from ImageMagick at http://www.fmwconcepts.com/imagemagick/fourier_transforms/fourier.html (Note some of the Jinc filtering is a bit outdated. Since I wrote that, Imagemagick implemented the Jinc function within -fx)
Here is a small set of commands to do it all in Unix syntax. Remove the +write ring.png if you do not want it to be created. This code is limited to square images.
ImageMagick 6:
inner=3
outer=40
infile="lena-1.png"
cent=`convert "$infile" -format "%[fx:floor((w-1)/2)]" info:`
inname=`convert "$infile" -format "%t" info:`
suffix=`convert "$infile" -format "%e" info:`
convert "$infile" \
\( +clone -fill black -colorize 100 \
-fill white -draw "translate $cent,$cent circle 0,0 0,$outer" \
-fill black -draw "translate $cent,$cent circle 0,0 0,$inner" \
-alpha off -blur 0x1 +write ring.png \
-write mpr:bpass +delete \) \
-fft \( -clone 0 mpr:bpass -compose multiply -composite \) \
-swap 0 +delete -ift -evaluate multiply 10 \
${inname}_bandpass_${inner}_${outer}.$suffix
ImageMagick 7 (only one command line):
inner=3
outer=40
infile="lena-1.png" \
magick "$infile" \
-set option:cent "%[fx:floor((w-1)/2)]" \
-set filename:fn "%t_bandpass_${inner}_${outer}.%e" \
\( +clone -fill black -colorize 100 \
-fill white -draw "translate "%[cent],%[cent]" circle 0,0 0,$outer" \
-fill black -draw "translate "%[cent],%[cent]" circle 0,0 0,$inner" \
-alpha off -blur 0x1 +write ring.png \
-write mpr:bpass +delete \) \
-fft \( -clone 0 mpr:bpass -compose multiply -composite \) \
-swap 0 +delete -ift -evaluate multiply 10 \
"%[filename:fn]"
If you mean band enhanced (band boost) and not band pass, then you add the result back with the original (-compose plus -composite). In ImageMagick 6, that would be:
inner=3
outer=40
infile="lena-1.png"
cent=`convert "$infile" -format "%[fx:floor((w-1)/2)]" info:`
inname=`convert "$infile" -format "%t" info:`
suffix=`convert "$infile" -format "%e" info:`
convert "$infile" \
\( +clone -fill black -colorize 100 \
-fill white -draw "translate $cent,$cent circle 0,0 0,$outer" \
-fill black -draw "translate $cent,$cent circle 0,0 0,$inner" \
-alpha off -blur 0x1 +write ring.png \
-write mpr:bpass +delete \) \
-fft \( -clone 0 mpr:bpass -compose multiply -composite \) \
-swap 0 +delete -ift "$infile" -compose plus -composite \
${inname}_bandenhance_${inner}_${outer}.$suffix
These are different results from what I get with those settings in ImageJ. Unfortunately, I do not know what they are doing. The ImageJ results look more like low pass filtering to me than what I know as band enhanced/band pass. See https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=12&cad=rja&uact=8&ved=2ahUKEwjJvoWD6L7eAhXJslQKHf1jArgQFjALegQICBAC&url=https%3A%2F%2Fcanvas.instructure.com%2Ffiles%2F6907524%2Fdownload%3Fdownload_frd%3D1&usg=AOvVaw2ws15jPD6C2-yAkfHmHYMH and https://www.scribd.com/doc/51981950/Frequency-Domain-Bandpass-Filtering-for-Image-Processing
In ImageJ, perhaps they are using a Butterworth filter or larger Gaussian blur. Or perhaps they are only processing the intensity channel from say HSI or HSV or LAB.

Weird Behaviour with New Lines Using grunt-exec

I am using ImageMagick and grunt-exec to generate a favicon for a website I am working on using the command found in the ImageMagick documentation.
convert image.png -bordercolor white -border 0 \
\( -clone 0 -resize 16x16 \) \
\( -clone 0 -resize 32x32 \) \
\( -clone 0 -resize 48x48 \) \
\( -clone 0 -resize 64x64 \) \
-delete 0 -alpha off -colors 256 favicon.ico
However I am getting some issues with line breaks which I think is partially because I do not fully understand what I should do with the line breaks.
In my Gruntfile.js I am currently using no line breaks and it works as expected. Notice that I had to remove all the line breaks and double escape the parentheses because apparently grunt-exec parses the string before it executes it.
exec: {
favicon: 'convert _favicon.svg -bordercolor white -border 0 \\( -clone 0 -resize 16x16 \\) \\( -clone 0 -resize 32x32 \\) \\( -clone 0 -resize 48x48 \\) \\( -clone 0 -resize 64x64 \\) -delete 0 -alpha off -colors 256 favicon.ico'
}
Like I said, I have it working right now but I would like to be able to use line breaks for readability and also because I would like to fully understand what is going on here. So far I have tried adding an extra \ and leaving everything the same, replacing the new lines with \n or \\n and putting everything on the same line but no luck.
The solution I was looking for turned out to be to use \n\ for new lines, like this:
convert image.png -bordercolor white -border 0 \n\
\( -clone 0 -resize 16x16 \) \n\
\( -clone 0 -resize 32x32 \) \n\
\( -clone 0 -resize 48x48 \) \n\
\( -clone 0 -resize 64x64 \) \n\
-delete 0 -alpha off -colors 256 favicon.ico
Try using this:
exec: {
favicon: 'convert _favicon.svg -bordercolor white -border 0 "( -clone 0 -resize 16x16 )" "( -clone 0 -resize 32x32 )" "( -clone 0 -resize 48x48 )" "( -clone 0 -resize 64x64 )" -delete 0 -alpha off -colors 256 favicon.ico'
}

Resources