snibgo's ImageMagick pages

Selective blur

We sometimes want to vary the amount of blur across an image, perhaps by using a mask: maximum blur where the mask is white, and no blur where the mask is black.

Blurring involves (in a sense) moving pixels. Thus the common technique of blending two images for a selective effect creates two superimposed images, a "ghosting". This may be undersirable and certainly creates a different effect. Methods shown here avoid this ghosting.

See also Image Mapped Effects: Variable Blur Mapping.

Binary masking

Create an artificial source of a repeating pattern with detail down to the pixel level.

%IM%convert ^
  xc:Black xc:gray(25%%) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone -negate ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone -fill Red -colorize 50 ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone -fill Lime -colorize 50 ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone -fill Blue -colorize 50 ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone -modulate 100,50,100 ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone -modulate 100,100,50 ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  ( +clone ) -append ^
  ( +clone -rotate 180 ) ^
  +append ^
  sb_src.png

set SRC=sb_src.png

for /F %%L in ('%IM%identify ^
  -format "WW=%%w\nHH=%%h" ^
  %SRC%') do set %%L
sb_src.png

Blur the entire source.

set BLUR_SIG=10

%IM%convert ^
  %SRC% ^
  -blur 0x%BLUR_SIG% ^
  sb_b1.png
sb_b1.png

Create a mask for the effect.

%IM%convert ^
  -size %WW%x%HH% xc:Black ^
  -draw "fill White rectangle 100,100 199,199" ^
  sb_rect_mask.png
sb_rect_mask.png

Apply the mask opacity to the blur.

%IM%convert ^
  %SRC% ^
  sb_b1.png ^
  sb_rect_mask.png ^
  -composite ^
  sb_rectmaskedBlur.png

The effect is analogous to placing a ground-glass screen over part of the image.

sb_rectmaskedBlur.pngjpg

We can soften the edge of the effect by blurring the mask before applying its opacity.

%IM%convert ^
  %SRC% ^
  sb_b1.png ^
  ( sb_rect_mask.png -blur 0x4 ) ^
  -composite ^
  sb_rectmaskedBlur2.png
sb_rectmaskedBlur2.pngjpg

Blur x or y

%IM%convert ^
  sb_src.png ^
  -morphology Convolve Blur:0x5 ^
  sb_blr_x.png
sb_blr_x.png
%IM%convert ^
  sb_src.png ^
  -morphology Convolve Blur:0x5,90 ^
  sb_blr_y.png
sb_blr_y.png

Varying blur sigma

Create a mask for the effect.

%IM%convert ^
  -size %WW%x%HH% radial-gradient: ^
  sb_mask.png

This mask graduates to the corners, not the edges.

See Gradients Cookbook for other possibilities.

sb_mask.png

Apply the mask opacity to the blur.

%IM%convert ^
  %SRC% ^
  sb_b1.png ^
  sb_mask.png ^
  -composite ^
  sb_maskedBlur.png

Detail is still visible except for a handful of pixels at the centre.

Although blur has occured elsewhere, it is visually overwhelmed by the strong detail in the image.

sb_maskedBlur.pngjpg

Use "-compose blur" to truly vary the blur.

%IM%convert ^
  %SRC% ^
  sb_mask.png  ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  sb_maskedBlur2.png

The blur at the centre is now full, and it correctly decreases towards the edges.

sb_maskedBlur2.pngjpg

Mask the blur with a cheaper method.

%IM%convert ^
  sb_mask.png -write mpr:MASK ^
  %SRC% ^
  +swap ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x0 -composite ^
  mpr:MASK ^
  -set option:compose:args 0x%BLUR_SIG% -composite ^
  sb_maskedBlur3.png

Compare the methods:

%IM%compare ^
  -metric RMSE ^
  sb_maskedBlur2.png sb_maskedBlur3.png ^
  NULL: 
cmd /c EXIT /B 0
1704.62 (0.0260108)
sb_maskedBlur3.pngjpg

By sending these two versions as layers in a Gimp image (see Gimp and IM) ...

call %PICTBAT%toGimp sb_maskedBlur2.png sb_maskedBlur3.png

... and blinking one layer on and off, we can see the difference is mostly in the corners, where there should be no blur. The cheaper method has introduced a small blur in these areas.

If we have a colour photograph, we can blur it with a radius proportional to the distance (in RGB space) each pixel is from a given colour.

Source photograph: toes.png.

set SRC_TOES=toes.png

%IM%identify -format %%[fx:mean] %SRC_TOES% 
0.488162
toes.png

Colour distance. See Making a picture greyscale.

Finds the distance to the closest of two colours, being the toes in shadow and the toes in sunshine.

call %PICTBAT%hashCol %SRC_TOES% -crop 10x10+116+86

set ONE_HASH_COL=%HASH_COL%

call %PICTBAT%hashCol %SRC_TOES% -crop 10x10+225+116

"%IM%convert" ^
  %SRC_TOES% ^
  ^( -clone 0 ^
    ^( +clone -fill %ONE_HASH_COL% -colorize 100 ^) ^
    -compose Difference -composite ^
    -grayscale RMS ^
  ^) ^
  ^( -clone 0 ^
    ^( +clone -fill %HASH_COL% -colorize 100 ^) ^
    -compose Difference -composite ^
    -grayscale RMS ^
  ^) ^
  -delete 0 ^
  -compose Darken -composite ^
  -auto-level ^
  sb_toes_cd.png
sb_toes_cd.pngjpg

Blur, applying the "colour distance" mask.

%IM%convert ^
  %SRC_TOES% ^
  sb_toes_cd.png  ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  sb_toes_cd_bld.png

%IM%identify -format %%[fx:mean] sb_toes_cd_bld.png 
0.497377
sb_toes_cd_bld.pngjpg

Repeat the above, blurring in RGB colorspace.

%IM%convert ^
  %SRC_TOES% ^
  -set colorspace sRGB -colorspace RGB ^
  sb_toes_cd.png  ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  -set colorspace RGB -colorspace sRGB ^
  sb_toes_cd_bldL.png

%IM%identify -format %%[fx:mean] sb_toes_cd_bldL.png 
0.502435
sb_toes_cd_bldL.pngjpg

The grass has been heavily blurred; the toes are blurred far less. We could apply a gamma < 1 to the mask, darkening it, reducing the blurring of the colours fairly close to the toes.

Green from grass has not spread into the pink toes. However, pink from the toes has spread into the green grass, reducing local contrast of both tone and hue. We can use the mask to make the toes (nearly) transparent so they don't participate (much) in the blur, then turn alpha off after the blur. See also Masking: read mask, which describes a technique for binary masks. I want continuous (not binary) masking, so I exclude the final step.

Blurring tends to remove outliers, so I also "-auto-level".

Apply the "colour distance" mask with read-mask.

%IM%convert ^
  %SRC_TOES% ^
  sb_toes_cd.png ^
  ( -clone 0-1 ^
    -alpha off -compose CopyOpacity -composite ^
  ) ^
  ( -clone 1 ) ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  -alpha off ^
  sb_toes_cd_bld2.png

%IM%identify -format %%[fx:mean] sb_toes_cd_bld2.png 
0.377058
sb_toes_cd_bld2.pngjpg

Repeat the above, transforming in RGB colorspace.

%IM%convert ^
  %SRC_TOES% ^
  -set colorspace sRGB -colorspace RGB ^
  sb_toes_cd.png ^
  ( -clone 0-1 ^
    -alpha off -compose CopyOpacity -composite ^
  ) ^
  ( -clone 1 ) ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  -alpha off ^
  -set colorspace RGB -colorspace sRGB ^
  sb_toes_cd_bld2L.png

%IM%identify -format %%[fx:mean] sb_toes_cd_bld2L.png 
0.461973
sb_toes_cd_bld2L.pngjpg

The result looks sharper as there is more contrast around the toes.

toes.png was cropped from a converted 14-bit camera raw file with minimal processing. An 8-bit/channel from the in-camera JPEG subjected to the same processing shows horrible quantum effects.

As we have a mask, we can use it to mask the unsharp operation so it will affect mostly the toes.

Sharpen.

%IM%convert ^
  sb_toes_cd_bld2.png ^
  -mask sb_toes_cd.png ^
  -unsharp 0x2 ^
  +mask ^
  sb_toes_cd_bld2u.png
sb_toes_cd_bld2u.pngjpg

Toytown effect

We can leave a horizontal line (or band) sharp with progressive blur above and below the line.

Make a "toytown" mask. See Clut Cookbook for the fx.

%IM%convert ^
  -size 1x%HH% gradient: ^
  -fx "V=u*1.5;V<1?V:2-V" ^
  -negate ^
  -scale "%WW%x%HH%^!" ^
  sb_mask2.png
sb_mask2.png

Apply the "toytown" mask.

%IM%convert ^
  %SRC% ^
  sb_mask2.png  ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  sb_masked2Blur.png
sb_masked2Blur.pngjpg

Running a toytown ("Tilt-shift") mask on a 7500x5000 pixel image took 354 seconds for the true method and 103 seconds for the cheaper method. The RMSE was 912.454 (0.0139231).

Varying blur x- and y-sigmas

By using different values in the red and green channels of the mask, we can independently vary the blur amounts in the x and y directions.

Make an x-y mask.

%IM%convert ^
  -size %HH%x%WW% gradient: -rotate 90 ^
  -size %WW%x%HH% gradient: ^
  xc:black ^
  -combine ^
  sb_maskxy.png
sb_maskxy.png

Apply the x-y mask.

%IM%convert ^
  %SRC% ^
  sb_maskxy.png  ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  sb_maskedxy.png

There is a visual problem top-left and bottom-right.

sb_maskedxy.pngjpg

Apply the gamma-changed x-y mask.

%IM%convert ^
  %SRC% ^
  ( sb_maskxy.png -gamma 0.5 ) ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x%BLUR_SIG% -composite ^
  sb_maskedxy2.png
sb_maskedxy2.pngjpg

Varying blur angle

By supplying two extra arguments, representing start and end angles, the blue channel of the mask will vary the rotation of the blur. This is pointless unless the x- and y-sigmas are different.

Create a varying-angle mask.

FOR /F %%i ^
IN ('%IM%identify -format "%%[fx:max(%WW%,%HH%)/2]" xc:') ^
DO set RMAX=%%i

set /A POL_WI=RMAX*3
set /A POL_HT=RMAX

%IM%convert ^
  -size %WW%x%HH% radial-gradient: -negate ^
  ( +clone ) ^
  ( -size %POL_HT%x%POL_WI% gradient: ^
    -rotate 90 ^
    +distort Polar ^"%RMAX%^" ^
    +repage -flop ^
    -gravity center -crop %WW%x%HH%+0+0 +repage ^
  ) ^
  -combine ^
  sb_maskang.png
sb_maskang.pngjpg

Apply the varying-angle mask.

%IM%convert ^
  %SRC% ^
  sb_maskang.png ^
  -compose Blur ^
  -set option:compose:args %BLUR_SIG%x0+0+360 -composite ^
  sb_maskedang.png

As radial-gradient continues to edges not corners,
the blur varies to the edges not corners.

sb_maskedang.pngjpg

The same but reversing the x and y sigmas.

%IM%convert ^
  %SRC% ^
  sb_maskang.png ^
  -compose Blur ^
  -set option:compose:args 0x%BLUR_SIG%+0+360 -composite ^
  sb_maskedang2.png

As radial-gradient continues to edges not corners,
the blur varies to the edges not corners.

sb_maskedang2.pngjpg

We can use the misnamed "-radial-blur" operator. The parameter is in degrees.

%IM%convert ^
  %SRC% ^
  -radial-blur 10 ^
  sb_radb.png
sb_radb.pngjpg

We can do a round-trip depolar/polar.

%IM%convert ^
  %SRC% ^
  -virtual-pixel Edge ^
  -set option:distort:scale 4   -distort DePolar -1 ^
  -virtual-pixel Tile ^
  -scale "5%%x100%%^!" -filter Gaussian -resize "2000%%x100%%^!" +filter ^
  -virtual-pixel HorizontalTile -background Black ^
  -set option:distort:scale .25 -distort Polar -1 ^
  sb_depol.png

But we have a sharp vertical line upwards from the centre.

sb_depol.png

Another round-trip depolar/polar.

%IM%convert ^
  %SRC% ^
  -virtual-pixel Edge ^
  -set option:distort:scale 4   -distort DePolar -1 ^
  -virtual-pixel Tile ^
  -resize "5%%x100%%^!" -filter Gaussian -resize "2000%%x100%%^!" +filter ^
  -virtual-pixel HorizontalTile -background Black ^
  -set option:distort:scale .25 -distort Polar -1 ^
  sb_depol2.png

We still have a sharp vertical line upwards from the centre.

sb_depol2.png

On depolar/polar, see the official Distorting: Polar Tricks and my own Polar distortions.

Blur fill

The blurFill.bat script can be regarded as a selective blur. For more details, see Filling holes: by blur. Here are some examples:

toes_holed.png

toes_holed.png
call %PICTBAT%blurFill ^
  toes_holed.png . sb_th1.png
sb_th1.png
call %PICTBAT%blurFill ^
  toes_holed.png 1+ sb_th1p.png
sb_th1p.png
call %PICTBAT%blurFill ^
  toes_holed.png . sb_th_mb1.png 1 225
sb_th_mb1.png
call %PICTBAT%blurFill ^
  toes_holed.png . sb_th_rb1.png 2 10
sb_th_rb1.png
call %PICTBAT%blurFill ^
  toes_holed.png . sb_th_rb2.png 2 45
sb_th_rb2.png

All images on this page were created by the commands shown, (except that to conserve bandwidth some PNG files were converted to JPG), using:

%IM%identify -version
Version: ImageMagick 6.9.5-3 Q16 x86 2016-07-22 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Visual C++: 180040629
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib cairo flif freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib

Source file for this web page is selblur.h1. To re-create this web page, execute "procH1 selblur".


This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.


Page version v1.0 29-Jan-2014.

Page created 07-Sep-2016 23:21:45.

Copyright © 2016 Alan Gibson.