viernes, 27 de marzo de 2015

PROMEDIO DE IMÁGENES

En algunas aplicaciones es necesario obtener un promedio sobre ciertas imágenes. Esto con el fin de sacar datos estadísticos o de otra índole para alguna prueba o propósito específico. Para poder llevar a cabo esto es necesario que las imágenes a las cuales se les calculará su valor promedio sean del mismo tamaño en píxeles a lo ancho y alto de la imagen.


     Para este ejemplo, se usarán dos imágenes con el mismo tamaño en píxeles de alto y ancho: 224x270.
     Primeramente se deben crear matrices que sean capaces de almacenar estas imágenes empleando 3 canales debido a que son imágenes a color. La instrucción:
cv::Mat imagenresultante = cv::Mat::zeros(alto, ancho, CV_32FC3);
Dice que la imagen a color será en 3 canales y se manejará con notación decimal, dado que hay que recordar que el máximo valor que puede tomar un píxel es 255, es decir si suma 250+200 le dará como resultado 255, si se pasa a flotante dará 450 y al dividir sobre 2 dará 225 el cual es el valor promedio del píxel.
   Por eso es importante que al final antes de desplegar la imagen resultante, convierta el valor nuevamente a entero sin signo de 8 bits. Un píxel puede variar su valor desde 0 a 255 para cada uno de los 3 canales de la imagen a color.
    La variable count, sirve para indicar el total de imágenes de las que se tomará el valor promedio, es importante que observe que tenga el mismo número de imágenes a las especificadas por la variable para evitar cualquier excepción en tiempo de ejecución.
    Para hacer el cambio a 8 bits sin signo, se aplica el comando:
imagenresultante.convertTo(imagenresultante,CV_8UC3);
      Dentro del ciclo for lo que resta es simplemente sumar imagen tras imagen y al final dividir entre el total cuyo valor está en la variable count.
      A continuación se le lista el código para poder llevar a cabo esta tarea:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;

int main()
{
    cv::Mat frame, tmp;
    const int count=2;
    const int ancho =224;
    const int alto = 270;
    cv::Mat imagenresultante = cv::Mat::zeros(alto, ancho, CV_32FC3);
    char nombrearchivo[50];
    for(int i=1; i<= count ; i++){
        sprintf(nombrearchivo,"cara%d.jpg",i);
        frame = imread(nombrearchivo, CV_LOAD_IMAGE_COLOR);
        frame.convertTo(tmp,CV_32FC3);
        imagenresultante += tmp;
        cout << "i = "<<i <<endl;
    }
    imagenresultante *= (1.0/count);

    imagenresultante.convertTo(imagenresultante,CV_8UC3);
    imshow("",imagenresultante);

    waitKey(0);
    return 0;
}

    Finalmente el resultado será algo similar a:


      Puede probar ahora usando más imágenes que tenga para ver resultados interesantes.



jueves, 12 de marzo de 2015

IDENTIFICACIÓN DE CONTORNO DE IMÁGENES

Introducción:
       La obtención de contorno también se le conoce como seguimiento de borde. El trazado de contorno es una técnica que se aplica a imágenes digitales para extraer sus bordes. La pregunta importante al analizar la imagen es: ¿Qué es un borde? Si sabemos que la imagen digital es un grupo de pixeles en un cuadro donde cada pixel tiene cierto valor. Para el caso básico una imagen puede ser transformada a escala de grises y con un valor de umbral a dos tonos (Blanco y Negro), segmentación de dos niveles, o imagen binarizada.
      El borde de un patrón dado 'P' es el conjunto de pixeles borde de P. Existen dos tipos de pixeles de borde:
      1) Pixeles de 4-bordes
          Un pixel negro se considera de 4-bordes si comparte al menos unos de sus bordes con un pixel blanco.
      2) Pixeles de 8-bordes
          Un pixel negro se considera de 8-bordes si comparte al menos uno de sus bordes con un pixel blanco.
    Un punto digno de remarcar es que no es suficiente con identificar los pixeles borde de un patrón  para extraer el contorno. Lo que se requiere es una secuencia ordenada de pixeles frontera que puedan extraer la forma general del patrón.

¿Por qué queremos obtener el contorno de un objeto en una imagen?
Respuestas:
     a) Para conocer su forma.
     b) Para clasificación de objetos.
Obtener el borde de una imagen nos da información suficiente para clasificarla conforme a su forma, Por ejemplo si se quiere identificar monedas sobre una mesa, un contorno tipo círculo nos diría en que parte de la mesa se encuentran.

OpenCV
           Esta biblioteca cuenta ya con los métodos necesarios para realizar está tarea. Como ejemplo, vea el siguiente código:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;

Mat color;
Mat gris;
RNG rng(12345);

int main()
{
    color =  imread("figuras-geometricas.jpg");

    // Mostramos la imagen con la que se va a trabajar
    namedWindow("IMAGEN COLOR",CV_WINDOW_AUTOSIZE);
    imshow("IMAGEN COLOR",color);

    // Se pasa la imagen de color a tono de grises para trabajar con ella
    cvtColor(color,gris,CV_RGB2GRAY);
    // Se binariza con un valor de umbral intermedio 128, para una mejor resolucion de las figuras
    threshold(gris,gris,128,255,CV_THRESH_BINARY);

    namedWindow("IMAGEN GRIS",CV_WINDOW_AUTOSIZE);
    imshow("IMAGEN GRIS",gris);

// Se prepara un vector para guardar los grupos de pixeles que conformarán el contorno.
    vector<vector<Point> > contornos;
    vector<Vec4i> resultado;

  findContours(gris,contornos,resultado,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,Point(0,0));

    /// Dibujar los  contornos
  Mat dibujo = Mat::zeros( gris.size(), CV_8UC3 );
  for( int i = 0; i< (uint16_t)contornos.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( dibujo, contornos, i, color, 2, 8, resultado, 0, Point() );
     }

  /// Mostralos en una ventana
  namedWindow( "CONTORNOS", CV_WINDOW_AUTOSIZE );
  imshow( "CONTORNOS", dibujo );



    cvWaitKey(0); // Espera a que se presione una tecla

    // Salir de la aplicación
    cvDestroyAllWindows();
}

Al ejecutar el código observará en cada una de las ventanas el seguimiento en el tratamiento de la imagen para la obtención de su contorno:


Referencia: 
Imagen tomada para fines explicativos de:
http://arte.about.com/od/Que-es-el-arte/fl/Figuras-geometricas.htm