[C++] Medir el diámetro de una pupila con OpenCV

Hoy les traigo uno de los trabajos que hice durante la que yo considero que fue mi clase más interesante de toda mi carrera. El programa que les mostrare a continuacion esta diseñado para medir el diametro de la pupila de un humano en una foto y fue creado apoyado en las librerias de OpenCVOpen Source Computer Vision Library.

Aunque sencillo, la comprension de este pequeño trabajo puede llevar a aplicaciones sumamente utiles, complejas y de tecnologia de punta como lo puede ser un sensor biometrico de retina.

Código

// PROGRAMA PARA MEDIR EL DIAMETRO DE UNA PUPILA CON OPENCV 
// Desarrollado por Oscar Garcia Oviedo, estudiante de la
// Universidad Autonoma de Ciudad Juarez en Mexico. 
// Profesor: M.I. Hiram Madero.
// Visto en http://www.acentoenlao.com

#include <iostream>

/// OPENCV LIBS /// -----------------------------------

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;  
using namespace std;

int main()  
{
    /// IMAGEN  /// -----------------------------------

    Mat imagen;     // Matriz que guardara la imagen

    imagen = imread("IMAGEN-ORIGINAL");


    /// EFECTOS /// -----------------------------------

    Mat imagen_aperture;    // Matriz que guardara la imagen procesada
    Mat elemento = getStructuringElement(MORPH_ELLIPSE, Size(5, 5), Point(0, 0));   // Estructura del kernel

    dilate(imagen, imagen_aperture, elemento);
    erode(imagen_aperture, imagen_aperture, elemento);
    erode(imagen_aperture, imagen_aperture, elemento);
    dilate(imagen_aperture, imagen_aperture, elemento);


    /// THRESHOLD /// -----------------------------------

    threshold(imagen_aperture, imagen_aperture, 30, 255, CV_THRESH_BINARY);



    /// CIRCULOS  /// ------------------------------------

    cvtColor(imagen_aperture, imagen_aperture, CV_RGB2GRAY, 1); // Conversion a escala de grises

    GaussianBlur(imagen_aperture, imagen_aperture, Size(5, 5), 1.5); // Blur gaussiano

    vector<Vec3f> circulos;

    HoughCircles(imagen_aperture, circulos, CV_HOUGH_GRADIENT,
                     2,
                     50,        // Distancia minima entre dos circulos
                     100,       // Canny Thr
                     100,
                     30, 50);   // Radio minimo y maximo

        vector<Vec3f>::const_iterator itc = circulos.begin();

        while(itc != circulos.end()){

            circle(imagen_aperture,
                   Point((*itc)[0], (*itc)[1]),     // Centro del circulo
                    (*itc)[2],                      // Radio del circulo
                    Scalar(255),                    // Color del circulo
                    2);                             // Grosor del circulo

            cout << "Diametro: " << (*itc)[2] * 2 << endl;
            ++itc;

        }


    /// RESULTADO /// -----------------------------------

    imshow("Circulos", imagen_aperture);    // Mostrar imagen resultado

    cvWaitKey(0);

}

NOTA: Tambien puede ser visto en GitHub!

Procedimiento

En palabras sencillas, el procedimiento realizado es el siguiente:

  1. En la seccion OPENCV LIBS se incluyen al programa las librerias esenciales para el funcionamiento de OpenCV y se define su sintaxis mediante el uso de using namespace cv;.
  2. En la seccion IMAGEN se crea una variable del tipo matriz y se define igual a la imagen original de la pupila.
  3. En la seccion EFECTOS se crea una variable del tipo matriz que servira para albergar la imagen modificada y se define la estructura del Kernel que se utilizara para los efectos de Apertura y Cierre aplicados posteriormente.
  4. En la seccion THRESHOLD se utiliza dicha funcion para convertir la imagen a binario, de forma que los pixeles con valores de RGB entre 30 y 255 son convertidos a blanco y los valores menos a 30 se convierten en negro.
  5. En la seccion CIRCULOS se convierte la imagen a escala de grises, lo que es necesario para aplicar un filtro gaussiano de emborronamiento que ayuda a suavizar y definir los bordes de la imagen. Despues se utiliza la funcion de circulos de Hough y se crea un vector para almacenar los datos de los circulos que se definen por la funcion de Hough. Finalmente, cuando se encuentra un circulo que cumple con lo especificado, el radio se multiplica por dos y se despliega el mensaje en la terminal.
  6. En la ultima seccion, llamada RESULTADOS se muestra la imagen totalmente procesada con el circulo que cumple nuestras especificaciones alrededor de la pupila.

Imagenes

Original

Imagen Original


Apertura

Efecto de apertura


Cierre

Efecto de cierre


Threshold

Threshold o umbral


Gaussian Blur

Emborronamiento gaussiano


Circulo

Deteccion de circulos


Resultado

Por ultimo, el resultado del programa es mostrado en la terminal.

Resultado

E indica que la pupila de la imagen mide aproximadamente 91.9348 pixeles.

Agradecimientos

Quiero agradecer a Hiram Madero por enseñarme un poquito de lo que sabe de OpenCV y programación en C++, y también por esta actividad durante su clase. Fueron buenos tiempos.

Gracias Alex por ver ese pequeño error que se me escapó.



Show Comments