OpenCV pour mesurer la qualité des images

Introduction

J’ai passé une autre soirée astro pour prendre des photos de Jupiter. Environ 220 clichés de plus ou moins bonne qualité, en fonction de l’atmosphère sont à trier. En général, certaines photos sont trop floues.

Comment faire le tri entre toutes ces photos pour ne garder que les plus nettes ? OpenCV va vous sauver la vie !

 

Principe

L’objectif est d’avoir un chiffre « qualité du focus », calculé sur chaque photo qui me permettra de trier mes 220 photos pour n’en sortir que les 100 plus nettes.

Pour ce faire, la technique la plus en vogue sur le net (stack overflow + publications) et de faire 2 filtres Sobel sur l’image, calculer les pics de gradients et faire une somme globale. Plus la somme est élevée, plus il y a de netteté.

 

Rappel / info à savoir

Sobel est un des filtres de détection des bords les plus connus (expliqué à la fac, dans des TP, etc). On peut citer aussi le Laplacien dans cette famille de filtres. Depuis une image en couleurs, ces filtres vont faire une image en dégradé de gris, avec :

  • en noir : les régions où il n’y a pas de bord (aplat de couleur ou changement doux)
  • en blanc : changement brutal de couleur (= un bord)

Ce qui est pratique avec Sobel, c’est qu’on peut lui dire dans quel axe il doit détecter les bords. Pour nous, ce sera un dans l’axe X et un dans l’axe Y de chaque image. Les pics de gradients se feront sur ces 2 axes pour avoir une large gamme de détection.

 

OpenCV

Ce n’est pas le premier script Python posté sur mon site qui utilise OpenCV. Pour ceux qui ne le savaient pas, Python a été créé à l’époque (au siècle dernier) pour interfacer du C/C++, donc faire des appels de fonctions programmées en C et compilées sur le PC. Ceci avec un langage plus simple que le C : le Python !

Bref, OpenCV propose une tonne de fonctions pour manipuler les images. Toutes, très éprouvées, très optimisées, et très math… (désolé pour les non-matheux)

 

Le script

Voici le script Python qui prend en entrée une liste d’images et sort un tri par netteté.

#!/usr/bin/python

import cv2, sys
import operator

files = sys.argv[1:]
all_ratio = {}
for filename in files:
    orig = cv2.imread(filename)

    sobel_dx = cv2.Sobel(orig, cv2.CV_64F, 1, 0, ksize=5)
    sobel_dy = cv2.Sobel(orig, cv2.CV_64F, 0, 1, ksize=5)
    magnitude_image = cv2.magnitude(sobel_dx,sobel_dy,sobel_dx);
    mag, ang = cv2.cartToPolar(sobel_dx, sobel_dy, magnitude_image) 

    ratio = cv2.sumElems(mag[0])
    all_ratio[filename] = ratio[0]

sorted_ratio = sorted(all_ratio.items(), key=operator.itemgetter(1))
index = 1
print(" Rang | Fichier      | Valeur calculee")
print("------|--------------|----------------")
for (filename, ratio) in reversed(sorted_ratio):
    print(" %04d | %s | %d" % (index, filename, ratio))
    index += 1

 

Exemple

Voici les 3 images utilisées dans l’appel du script (cliquez pour voir la photo originale) :

  • Image « apero girl.png », originale :
  • image « apero girl-5.png », copie de l’image originale, avec un flou gaussien de 5px :
  • image « apero girl-20.png », copie de l’image originale, avec un flou gaussien de 20px :

Résultat du script :

 Rang | Fichier      | Valeur calculee
------|--------------|----------------
 0001 | apero girl.png | 154324
 0002 | apero girl-5.png | 146422
 0003 | apero girl-20.png | 142630

Conclusion : l’image « apero girl.png » est le plus net.

 

Remarque

En regardant le script « dans le blanc des yeux », on serait tenté de dire ceci : oui, mais ton script ne te donne de bons résultats uniquement sur des photos proches, d’une prise de vue d’un même objet, qui serait plus ou moins flou.

Et bien, en effet, si on prend 2 photos qui n’ont rien à voir, les indices calculés seront incohérents et le tri par « qualité de netteté » ne voudra rien dire.

Donc, restez vigilant à ne passer dans ce script que des photos d’un même objet, dont la netteté varie.

 

2 réflexions au sujet de « OpenCV pour mesurer la qualité des images »

  1. Merci pour les informations Mr. Julien. Ce traitement fait partie de mon PFE, mais je ne maîtrise pas le python, je voudrais s’il vous plaît et si c’est possible demander votre aide pour avoir l’équivalent de ce code en C++ et merci d’avance.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>