snibgo's ImageMagick pages

Camera blurs

Digital blurring is usually Gaussian, or something close. Cameras defocus differently.

Photographic blur comes from two phenomena:

This page is about focus blur.

Light from a point of the object doesn't hit a single point on the sensor. Instead, it is spread across an area. The size of the area depends on how out-of-focus the camare is, and the size of the lens aperture. The shape of the area depends on the shape of the lens aperture.

Here is a photo of a Noct-Nikkor 58mm f/1.2 lens, stopped down to f/2.8 and f/8 and f/1.2. A Nikkor 105mm set to f/2.8 and f/8.

It's irrelevant, but they were photographed with a Nikkor 50/2 on a D800 at f/4, about 1/30s, ISO 200, handheld. The background is a laptop screen.

set CRAD=3

%IM%convert ^
  -size 100x200 ^
  xc:#000 ^
  xc:#fff ^
  xc:#888 ^
  -fill #fff -draw "translate 50,40 circle 0,0 0,%CRAD%" ^
  -fill #f00 -draw "translate 50,80 circle 0,0 0,%CRAD%" ^
  -fill #0f0 -draw "translate 50,120 circle 0,0 0,%CRAD%" ^
  -fill #00f -draw "translate 50,160 circle 0,0 0,%CRAD%" ^
  +append ^
  +depth ^
  cb_samp.png
cb_samp.png

Gaussian blur

Digital blur is commonly Gaussian. This is not how cameras blur images.

set /A RAD=15
set /A DIAM=%RAD%+%RAD%+1

%IM%convert ^
  xc:White ^
  -bordercolor Black -border %RAD% ^
  -gaussian-blur 0x5 ^
  +depth cb_g1.png
cb_g1.png

Polygons

The script polyPath.bat, given a centre, radius and number of points, builds a path string representing a regular polygon, in the form Mx,y,Lx,y,...Lx,yZ. The result can be used in a "-draw" command to create the polygon.

set /A RAD=15
set /A DIAM=%RAD%+%RAD%+1

call %PICTBAT%polyPath %RAD% %RAD% %RAD% 2

%IM%convert ^
  -size %DIAM%x%DIAM% xc:#000 -fill #fff -draw "path '%ppPATH%'" ^
  +depth cb_poly2.png
cb_poly2.png
call %PICTBAT%polyPath %RAD% %RAD% %RAD% 3

%IM%convert ^
  -size %DIAM%x%DIAM% xc:#000 -fill #fff -draw "path '%ppPATH%'" ^
  +depth cb_poly3.png
cb_poly3.png
call %PICTBAT%polyPath %RAD% %RAD% %RAD% 4

%IM%convert ^
  -size %DIAM%x%DIAM% xc:#000 -fill #fff -draw "path '%ppPATH%'" ^
  +depth cb_poly4.png
cb_poly4.png
call %PICTBAT%polyPath %RAD% %RAD% %RAD% 5

%IM%convert ^
  -size %DIAM%x%DIAM% xc:#000 -fill #fff -draw "path '%ppPATH%'" ^
  +depth cb_poly5.png
cb_poly5.png
call %PICTBAT%polyPath %RAD% %RAD% %RAD% 6

%IM%convert ^
  -size %DIAM%x%DIAM% xc:#000 -fill #fff -draw "path '%ppPATH%'" ^
  +depth cb_poly6.png
cb_poly6.png
call %PICTBAT%polyPath %RAD% %RAD% %RAD% 7

%IM%convert ^
  -size %DIAM%x%DIAM% xc:#000 -fill #fff -draw "path '%ppPATH%'" ^
  +depth cb_poly7.png
cb_poly7.png

We can convert any of these into a finite Gaussian kernel. First, we make a linear gradient using "-morphology Distance". Then we clut it with the result of a process module (see Process modules: mkgauss), but "-sigmoidal-contrast" would give a close approximation instead.

%IMDEV%convert ^
  cb_poly5.png ^
  -morphology Distance "Euclidean:7" ^
  -auto-level ^
  -write cb_p5d.png ^
  -process "mkgauss zeroize cumul norm" ^
  -clut ^
  cb_p5g.png
cb_p5d.png cb_p5g.png
%IMDEV%convert ^
  cb_poly5.png ^
  -morphology Distance "Euclidean:7" ^
  -auto-level ^
  -sigmoidal-contrast 7,50%% ^
  cb_p5sg.png
cb_p5sg.png

Read into a kernel (see Process modules: img2knl):

for /F "usebackq" %%L in (`%IMDEV%convert ^
  cb_poly5.png -process img2knl NULL:`) do set KNL=%%L

Blur with this kernel:

%IM%convert ^
  cb_samp.png ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNL% ^
  cb_conv1.png
cb_conv1.png

Blur in linear colorspace:

%IM%convert ^
  cb_samp.png ^
  -colorspace RGB ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNL% ^
  -colorspace sRGB ^
  cb_conv2.png
cb_conv2.png

Blur in sub-linear colorspace:

%IM%convert ^
  cb_samp.png ^
  -evaluate Pow 5 ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNL% ^
  -evaluate Pow 0.2 ^
  cb_conv3.png
cb_conv3.png

Doughnut kernel, aka bad bokeh (see Wikipedia: Bokeh):

blah:

%IM%convert ^
  cb_poly5.png ^
  cb_p5g.png ^
  -compose Mathematics -define compose:args=0,-0.5,1,0 -composite ^
  cb_k_dn1.png
cb_k_dn1.png

Read into a kernel:

for /F "usebackq" %%L in (`%IMDEV%convert ^
  cb_k_dn1.png -process img2knl NULL:`) do set KNLD=%%L

echo KNLD=%KNLD%

Blur with this kernel:

%IM%convert ^
  cb_samp.png ^
  -define showkernel=1 ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNLD% ^
  cb_conv1d.png
cb_conv1d.png

Blur in linear colorspace:

%IM%convert ^
  cb_samp.png ^
  -colorspace RGB ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNLD% ^
  -colorspace sRGB ^
  cb_conv2d.png
cb_conv2d.png

Blur in sub-linear colorspace:

%IM%convert ^
  cb_samp.png ^
  -evaluate Pow 5 ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNLD% ^
  -evaluate Pow 0.2 ^
  cb_conv3d.png
cb_conv3d.png

Each kernel is a point spread function (PSF, see Wikipedia Point spread function). It defines how a point of light is spread. We can demonstrate this by convolving a point source with one of the kernels.

Create a point source:

%IM%convert ^
  xc:White ^
  -bordercolor Black ^
  -border 30 ^
  cb_pnt.png
cb_pnt.png

Convolve the point source:

%IM%convert ^
  cb_pnt.png ^
  -define convolve:scale="^!" ^
  -morphology convolve %KNLD% ^
  -auto-level ^
  +depth ^
  cb_convpnt1.png
cb_convpnt1.png

The result, cropped to the size of the kernel, is (more or less) identical to the kernel.

%IM%convert ^
  cb_convpnt1.png ^
  -gravity Center -crop %DIAM%x%DIAM%+0+0 +repage ^
  cb_k_dn1.png ^
  -metric RMSE -compare ^
  -format %%[distortion] ^
  info: 
0.00637442

Catadioptric (mirror) lenses

blah

Cataracts

blah

Deblurring

Deblurring a photograph needs two steps:

  1. Find the appropriate kernel.
  2. Deconvolve with this kernel.

If the kernel is known, deblurring is a process of deconvolution. When the kernel is not known the process is called "blind deconvolution".

The PSF (kernel) for camera-shake might be approximately constant across the image for rotation of the camera about a horzontal or vertical axis. It will not be constant for out-of-focus areas; these need different sizes of PSFs, and PSF rotation depending on whether the object is in front of or behind the plane of focus.

If the PSF is not correct, the result will suffer from ringing.

A interesting reference for camera-shake is Removing Camera Shake from a Single Photograph, Fergus et al, which chiefly addresses the difficult problem of finding the PSF.

The Fergus paper uses Richarson-Lucy deconvolution, which doesn't seem difficult. See Wikipedia: Richardson-Lucy deconvolution.

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

polyPath.bat

rem From:
rem  %1,%2 coords of centre
rem  %3 radius from centre to each apex
rem  %4 number of sides
rem  %5 optional rotation
rem returns ppPATH set to M...Z path, no spaces.

@if "%4"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

@call echoOffSave


set sPath=M

set /A Nm1=%4-1

echo %Nm1%

set ROT=%5
if "%ROT%"=="" set ROT=0

for /L %%i in (0,1,%Nm1%) do (

  for /F "usebackq" %%F in (`%IM%identify -ping -precision 15 ^
    -format "ANG=%%[fx:(%%i*360/%4+%ROT%)*pi/180]" ^
    xc:`) do set %%F

  echo ANG=!ANG!

  for /F "usebackq" %%F in (`%IM%identify -ping -precision 15 ^
    -format "DX=%%[fx:sin(!ANG!)*%3+%1]\nDY=%%[fx:cos(!ANG!)*%3+%2]" ^
    xc:`) do set %%F

  echo !DX!,!DY!

  if not %%i==0 set sPath=!sPath!L
  set sPath=!sPath!!DX!,!DY!
)

call echoRestore

set sPath=!sPath!Z
echo sPath=%sPath%

@endlocal & set ppPATH=%sPath%

All images on this page were created by the commands shown, using:

%IM%identify -version
Version: ImageMagick 6.9.1--6 Q16 x64 2015-06-20 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib cairo freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG to JPG.

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


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 9-November-2014.

Page created 13-Oct-2015 19:46:45.

Copyright © 2015 Alan Gibson.