Some metrics for blurriness.
If we have a reference image and a blurred version, we can measure the difference (eg RMSE) caused by the blur. But we might not have a reference, merely a blurred version. Here are some ways of measuring blurriness of individual images.
We might use standard deviation, either of the entire image, or of the average (or maximum) SD of a sliding window. (Sliding window SD is fast when calculated by integral images). However, SD is independent of pixel locations. It measures contrast, either overall or within each window, but says nothing about whether the pixels are arranged to give a smooth gradient or sharp boundary.
A more complex method, described in a paper by Crete et al, is sometimes used. In a nutshell: we blur the image, and see how much it has changed. If it has changed a lot then it was sharp, but if it didn't change much then it was already blurred.
We take a grayscale image and its blur in one dimension, and the slope magnitude of each. This is a measure of high-freqency amplitude, that blurring attenuates. Subtract the slope magnitudes to get the variation. Where the variation is high, the blur has removed high frequencies. Where the variation is low or zero, blurring has not removed high frequencies so it was already blurred.
The paper gives an algorithm:
If we take the paper literally: VVer and VHor are calculated but never used; D_VVer and D_VHor are used but never calculated. So I suppose the prefix D_ has been accidentally omitted.
The blur can be done with "-statistic Mean" or "-process integim", giving slightly different results due to different treatment at edges.
Summing pixels could be done by "-process integim" and using the last pixel, but we need one sum divided by another sum from same-sized images, so instead we can use "-scale 1x1!" to get the means.
If the input images have pixel values in the range 0 to 100%, then all intermediate images are also in that range, so HDRI is not required to cope with OOG. If we use "-process integim", that needs HDRI. Also, we calculate differences between adjacent pixels, and these are small numbers so we could easily lose precision when we take the mean and then divide, so HDRI is a good idea.
The script measureBlur.bat implements this. Here are some examples, also showing some standard deviation (SD) statistics.
Note that:
For each example, we calculate and show four statistics:
mb_score is calculated from intensity only. In these examples, the SD measurements are from all channels.
%IMG7%magick ^ toes.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur toes.png call %PICTBAT%iiWinSD toes.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0.153221 mb_score=0.4861911216334783 wsdMeanSD=0.04570518 wsdMaxSD=0.23287024 |
|
%IMG7%magick ^ toes.png ^ -blur 0x1 ^ +write mb_blr.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur mb_blr.png call %PICTBAT%iiWinSD mb_blr.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0.150146 mb_score=0.636357719157702 wsdMeanSD=0.039165829 wsdMaxSD=0.21599624 |
|
%IMG7%magick ^ toes.png ^ -unsharp 0x1 ^ +write mb_usm.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur mb_usm.png call %PICTBAT%iiWinSD mb_usm.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0.155273 mb_score=0.4453480249103532 wsdMeanSD=0.049572325 wsdMaxSD=0.24469792 |
|
%IMG7%magick ^ toes.png ^ -blur 0x20 ^ +write mb_blr2.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur mb_blr2.png call %PICTBAT%iiWinSD mb_blr2.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0.0960485 mb_score=0.993745171950103 wsdMeanSD=0.0065275174 wsdMaxSD=0.021335356 |
|
%IMG7%magick ^ toes.png ^ -colorspace Gray ^ -auto-gamma ^ +dither -posterize 2 ^ +write mb_bw.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur mb_bw.png call %PICTBAT%iiWinSD mb_bw.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0.498908 mb_score=0.1347216659037156 wsdMeanSD=0.16117698 wsdMaxSD=0.5 |
|
%IMG7%magick ^ toes.png ^ -fill #abc -colorize 100 ^ +write mb_col.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur mb_col.png call %PICTBAT%iiWinSD mb_col.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0 mb_score=1 wsdMeanSD=1.8558487e-07 wsdMaxSD=1.7059715e-06 |
|
Sort the pixels in toes.png: %IM7DEV%magick ^ toes.png ^ -set option:WW %%w ^ -crop x1 +repage ^ +append +repage ^ -intensity Rec709Luminance ^ -process sortpixels ^ -flop ^ -crop %%[WW]x1 ^ -append +repage ^ +write mb_srt.png ^ -format "SD=%%[fx:standard_deviation]\n" ^ info: call %PICTBAT%measureBlur mb_srt.png call %PICTBAT%iiWinSD mb_srt.png 9x9 echo mb_score=%mb_score% echo wsdMeanSD=%wsdMeanSD% echo wsdMaxSD=%wsdMaxSD% SD=0.15322096 mb_score=0.7227789182307164 wsdMeanSD=0.037480198 wsdMaxSD=0.07201522 The SD is unchanged from toes.png,
|
There is a fairly good correlation:
wsdMaxSD * 2 = 1 - mb_score
... roughly speaking.
For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.
rem From image %1, rem writes No-Reference Perceptual Blur Metric rem to environment variable %2 [default mb_score]. rem %3 is prefix for debugging images. Default: no images. @rem @rem Reference: http://im.snibgo.com/measblur.htm @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 mb set ENVVAR=%2 if "%ENVVAR%"=="." set ENVVAR= if "%ENVVAR%"=="" set ENVVAR=mb_score set DBG_PREF=%3 if "%DBG_PREF%"=="" ( set WR_F= set WR_BHOR= set WR_BVER= set WR_D_FVER= set WR_D_FHOR= set WR_D_BVER= set WR_D_BHOR= set WR_D_VVER= set WR_D_VHOR= ) else ( set WR_F=+write %DBG_PREF%_f set WR_BHOR=+write %DBG_PREF%_bhor set WR_BVER=+write %DBG_PREF%_bver set WR_D_FVER=+write %DBG_PREF%_d_fver set WR_D_FHOR=+write %DBG_PREF%_d_fhor set WR_D_BVER=+write %DBG_PREF%_d_bver set WR_D_BHOR=+write %DBG_PREF%_d_bhor set WR_D_VVER=+write %DBG_PREF%_d_vver set WR_D_VHOR=+write %DBG_PREF%_d_vhor ) set TMPDIR=\temp\ for /F "usebackq" %%L in (`%IMG7%magick ^ %INFILE% ^ -colorspace Gray ^ %WR_F% ^ +write mpr:F ^ ^( +clone ^ -statistic Mean 9x1 ^ %WR_BHOR% ^ +write mpr:bhor ^ +delete ^) ^ ^( +clone ^ -statistic Mean 1x9 ^ %WR_BVER% ^ +write mpr:bver ^ +delete ^) ^ ^( +clone ^) ^ -geometry +0-1 ^ -compose Difference -composite ^ -geometry +0+0 ^ %WR_D_FVER% ^ +write mpr:d_fver ^ +delete ^ mpr:F ^( +clone ^) ^ -geometry -1+0 ^ -compose Difference -composite ^ -geometry +0+0 ^ %WR_D_FHOR% ^ +write mpr:d_fhor ^ +delete ^ mpr:bver ^( +clone ^) ^ -geometry +0-1 ^ -compose Difference -composite ^ -geometry +0+0 ^ %WR_D_BVER% ^ +write mpr:d_bver ^ +delete ^ mpr:bhor ^( +clone ^) ^ -geometry -1+0 ^ -compose Difference -composite ^ -geometry +0+0 ^ %WR_D_BHOR% ^ +write mpr:d_bhor ^ +delete ^ mpr:d_fver mpr:d_bver ^ -compose MinusSrc -composite -clamp ^ %WR_D_VVER% ^ +write mpr:d_vver ^ +delete ^ mpr:d_fhor mpr:d_bhor ^ -compose MinusSrc -composite -clamp ^ %WR_D_FHOR% ^ +write mpr:d_vhor ^ +delete ^ ^( mpr:d_vver mpr:d_fver ^ -scale "1x1^!" ^ -compose DivideSrc -composite ^ ^) ^ ^( mpr:d_vhor mpr:d_fhor ^ -scale "1x1^!" ^ -compose DivideSrc -composite ^ ^) ^ -compose Darken -composite ^ -negate ^ -precision 16 ^ -format "SCORE=%%[fx:mean]\n" ^ info:`) do set %%L call echoRestore @endlocal & set mbOUTFILE=%OUTFILE%& set %ENVVAR%=%SCORE%
rem From image %1, rem calculates numeric mean and maximum windowed standard deviation. rem using the process module integral image method. rem %2 window size eg 3x3 @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 wsd set WINDIMS=%2 if "%WINDIMS%"=="." set WINDIMS= if "%WINDIMS%"=="" set WINDIMS=3x3 for /F "usebackq" %%L in (`%IM7DEV%magick ^ %INFILE% ^ ^( -clone 0 ^ -evaluate Pow 2 ^ -process 'integim' ^ -process 'deintegim window %WINDIMS%' ^ ^) ^ ^( -clone 0 ^ -process 'integim' ^ -process 'deintegim window %WINDIMS%' ^ -evaluate Pow 2 ^ ^) ^ -delete 0 ^ -alpha off ^ -compose MinusSrc -composite ^ -evaluate Pow 0.5 ^ -format "MeanSD=%%[fx:mean]\nMaxSD=%%[fx:maxima]\n" ^ info:`) do set %%L call echoRestore endlocal & set wsdMeanSD=%MeanSD%& set wsdMaxSD=%MaxSD%
All images on this page were created by the commands shown, using:
%IMG7%magick -version
Version: ImageMagick 7.1.1-20 Q16-HDRI x86 98bb1d4:20231008 https://imagemagick.org Copyright: (C) 1999 ImageMagick Studio LLC License: https://imagemagick.org/script/license.php Features: Cipher DPC HDRI OpenCL OpenMP(2.0) Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib Compiler: Visual Studio 2022 (193532217)
To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.
Source file for this web page is measblur.h1. To re-create this web page, execute "procH1 measblur".
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 8-August-2018.
Page created 02-Mar-2024 17:37:18.
Copyright © 2024 Alan Gibson.