Flying memes

Face recognition con Ruby e OpenCV

Update – 18/06 : ieri sera ho tenuto una presentazione su questo tema al Ruby Social Club: ne approfitto quindi per aggiornare questo post con il link alle slide che ho utilizzato.

Negli ultimi mesi sono emerse le prime applicazioni che fanno uso di algoritmi di riconoscimento oggetti e, più specificatamente, volti. Cito, ad esempio, Picasa ed il filtro per visionare solo le facce in Google Images ma la lista di chi ha deciso di incorporare al suo interno questa funzionalità è decisamente più lunga.

Mi sono interessato subito al lato tecnico di questa nuova feature (grazie anche ad un ottimo speech ascoltato all’Erukuo 2009) imbattendomi in un particolare classificatore chiamato ‘cascade of boosted classifiers working with haar-like features’ che funziona nel seguente modo:

  1. Attraverso un training set viene generato un descrittore delle variazioni  di contrasto più comuni per un particolare oggetto (contrasto e orientamento);
  2. Tale descrittore, che intrinsecamente ha una sua dimensione (quella delle immagini con le quali è stato creato), viene fatto scorrere sull’imagine da identificare ridimensionandolo ad ogni passaggio (in modo da ‘intercettare’ possibili oggetti anche di dimensioni diverse rispetto a quelle del training set);
  3. Il descrittore presenta a sua volta una struttura ‘incrementale’ nella quale esso è composto da una sequenza di filtri che vengono verificati in sequenza sulla regione di interesse finche un filtro non fallisce o tutti i filtri passano, certificando in questo modo il match.
  4. Ogni filtro è, concludendo, creato da una serie di operazioni basilari, che vengono anch’esse applicate in sequenza sulla regione di interesse; il risultato in questo caso è misurato pesando i risultati delle singole operazioni.

Sfruttando un esempio creato da Cory Forsyth ho costruito un face detector ‘seriale’, capace di applicare più descrittori su più immagini, creando in output una pagina html che evidenzi, per ogni immagine, le aree riconosciute come appartenenti ad un oggetto.

Ecco il codice:


require 'rubygems'
require 'opencv'

face_detectors = %w(
  /usr/local/share/opencv/haarcascades/haarcascade_frontalface_default.xml
  # inserire qui l'elenco dei descrittori da utilizzare
).collect { |fd| OpenCV::CvHaarClassifierCascade::load(fd) }

file_names =  Dir.glob(ARGV[0] || "/Users/sandro/Ruby/image_labs/lib/facer/euruko2/*.jpg") 

file_names.each_with_index do |file_name,i|

  face_rectangles = []
  opencv_load = OpenCV::IplImage.load(file_name)
  face_detectors.each_with_index do |face_detector,k|
    face_detector.detect_objects(opencv_load).each do |rect|
      face_rectangles << [
        rect.top_left.x,      rect.top_left.y,
        rect.top_right.x    - rect.top_left.x,
        rect.bottom_left.y  - rect.top_left.y
      ]
    end
  end

  File.open("#{File.basename(file_name)}.html","w") do |file|
    file.write <<-HTML
      <html>
         <body style="margin:0px; background: url('file://#{file_name}') no-repeat top left;">
          #{  face_rectangles.collect do |(x,y,w,h)|
                " <div class=\"face\" style=\"position: absolute; left: #{x}px;
                  top: #{y}px; width: #{w}px; height: #{h}px; border: 2px solid red; \"></div>"
              end.join("\n") }
         </body>
       </html>
    HTML
  end

  puts "End #{file_name}"

end

Unico requisito per il corretto funzionamento del tutto è l’installazione di OpenCV, una libreria opensource che contiene una serie di strumenti dedicati alla ‘real time computer vision’, tra i quali figurano anche algoritmi di Face Recognition. Installare OpenCV ed i necessari binding per Ruby non è esattamente una procedura semplicissima, l’intera sequenza è però ottimamente illustrata in questo how-to.

Chiudo questo post con un link ad una pagina html generata utilizzando il programmino di cui sopra, potete notare come seppur il risultato in termini di riconoscimento sia ottimo vi siano pure dei falsi positivi. Una possibile tecnica di rimozione potrebbe essere modificare l’elenco dei descrittori, magari riducendolo,  in questo modo però si incorre nella possibilità di non individuare correttamente alcuni volti.

Tags: , ,