23
$\begingroup$

I need to filter out blurry or otherwise bad quality images from a set. I would like an efficient method to detect images that have any of the following three attributes:

  1. Out of focus or motion blur
  2. Lens occlusions: particles (hair or dust), smudges or hand/fingers over the lens
  3. Poorly lighted over or under exposed images.
$\endgroup$
  • 4
    $\begingroup$ Related: stackoverflow.com/questions/7765810/… $\endgroup$ – Niki Estner Jan 14 '15 at 16:35
  • $\begingroup$ I think an optimal solution will likely consider the "circle of confusion" in an out-of-focus image. $\endgroup$ – Mr.Wizard Jan 14 '15 at 16:40
  • 4
    $\begingroup$ Can you post a couple of samples to play with? Have you tried a GradientFilter? $\endgroup$ – Szabolcs Jan 14 '15 at 16:52
  • 2
    $\begingroup$ Also, just to be nitpicky :) This image is in fact very much out of focus. Now I really do wonder how cameras evaluate focus based on the recorded image. $\endgroup$ – Szabolcs Jan 14 '15 at 16:56
  • 1
    $\begingroup$ You could probably use a convolutional neuronal network to classify the images (or random sampled parts of larger images). I would assume that such a network would learn some kind of gradient filters in the first layers and build up logic from there. $\endgroup$ – Sascha Dec 8 '16 at 6:01
32
$\begingroup$

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

enter image description here

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.

            enter image description here

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:

            enter image description here

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@"http://i.stack.imgur.com/KoXDo.jpg",
   city1 = Import@"http://i.stack.imgur.com/UOH7V.jpg",
   city2 = Import@"http://i.stack.imgur.com/L0yMA.jpg",
   city3 = Import@"http://i.stack.imgur.com/LCOpK.jpg"};

lena

enter image description here

pentagon

enter image description here

park

enter image description here

city1

enter image description here

city2

enter image description here

city3

enter image description here

Results

outOfFocus /@ imgs

enter image description here

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"}]

enter image description here

$\endgroup$
  • 2
    $\begingroup$ It's nice to have you actively posting again. :-) $\endgroup$ – Mr.Wizard Jan 15 '15 at 19:24
  • 1
    $\begingroup$ The present code is rather slow. This large image took 24 seconds to process. How might one optimize this? $\endgroup$ – Mr.Wizard Jan 15 '15 at 19:28
  • $\begingroup$ Although it displays depth of field this image would not generally be considered out of focus yet your function returns a value of 4.98737. Thoughts? $\endgroup$ – Mr.Wizard Jan 15 '15 at 19:31
  • $\begingroup$ @Mr.Wizard one may downsample large images provided it is not done to such an extent as to degrade the contrast at high spatial frequencies. I also disagree about the second image; the majority of it is in fact out of focus, even if the focal point is included in the scene. $\endgroup$ – Oleksandr R. Jan 15 '15 at 19:35
  • 1
    $\begingroup$ @Mr.Wizard Big images: one can check downsampled image, then some randomly picked pieces. DOF: your image is very bright so it is difficult to find local maximums. This one gives 0.9, which is close to values of focused images. Anyway, there are many possibilities to tune parameters and optimize algorithm. No other algorithms which I tried, couldn't distinguish city1 and city3 :-) $\endgroup$ – ybeltukov Jan 15 '15 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.