As was correctly noted in comments, out-of-focus images cannot been correctly detected by a simple gradient filter since out-of-focus images can have sharp edges. I propose another simple idea to detect such images.
Introduction
Roughly speaking, the brightness of a defocused image $B(x,y)$ is a convolution of a focused image $B_0(x',y')$ with some kernel $K$
$$
B(x,y) = \int K(x-x',y-y')B_0(x',y')dx\,dy.
$$
Typically, $K$ is something like DiskMatrix
in Mathematica. However, pixel values nonlinearly depend on brightness (or exposure) because of the logarithmic scale in the following figure
Therefore, the real brightness exponentially depends on the pixel value $V(x,y)$. The exponential function is nonlinear so the defocusing is not a convolution in terms of $V(x,y)$. However, the exponential function grows very fast so we can approximately write
$$
V(x,y) = \max_{(x-x')^2+(y-y')^2<r^2} V_0(x',y').
$$
So defocusing is rather Dilation
(wiki) than ImageConvolve
. Indeed, dilated image looks like real out of focus image.
Dilation has an interesting property: there is no sharp local maximums of pixel values. All local maximums cover some area (circle with radius $r$ at least). There is an appropriate function MaxDetect
. It gives:
There is a lot of tiny areas in the focused images and only big areas in the defocused image.
Filter
Thus, we can introduce a simple out-of-focus measure, which is based on MaxDetect
and ComponentMeasurements
(these default values of thr
and q
is better then thr=0.15
and q=0.9
which I used in the first revision)
outOfFocus[img_Image, thr_: 0.05, q_: 0.8] :=
Quantile[ComponentMeasurements[#, "Area"][[All, 2]]/
ComponentMeasurements[#, "PerimeterLength"][[All, 2]], q] &@MaxDetect[img, thr];
Tests
Some test images
imgs = {
lena = ExampleData@{"TestImage", "Lena"},
pentagon = ExampleData@{"AerialImage", "Pentagon"},
park = Import@"https://i.sstatic.net/KoXDo.jpg",
city1 = Import@"https://i.sstatic.net/UOH7V.jpg",
city2 = Import@"https://i.sstatic.net/L0yMA.jpg",
city3 = Import@"https://i.sstatic.net/LCOpK.jpg"};
lena
pentagon
park
city1
city2
city3
Results
outOfFocus /@ imgs
Out of focus images have bigger values, so you can introduce some threshold around 0.8. outOfFocus
works fine with artificial blurring and dilation as well
Plot[{Unevaluated@outOfFocus@Blur[lena, r],
Unevaluated@outOfFocus@Dilation[lena, DiskMatrix@r]}, {r, 0, 4},
PlotPoints -> 10, MaxRecursion -> 0, PlotRange -> {0, All},
PlotLegends -> {"Blur", "Dilation"},
AxesLabel -> {"r", "outOfFocus"}]
GradientFilter
? $\endgroup$