domingo, 19 de abril de 2015

Histograma de una imagen - Opencv

Histograma según Wikipedia

En las imágenes digitales un histograma de color representa el número de pixeles que tienen colores en cada una de las listas fijas de rangos de colores, que se extienden sobre el espacio de color de la imagen, es decir el conjunto de todos los posibles colores. "

histogram.h



#if !defined HISTOGRAM
#define HISTOGRAM
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>

class Histogram1D {

  private:

    int histSize[1];
    float hranges[2];
    const float* ranges[1];
    int channels[1];

  public:

    Histogram1D()
    {

        // Preparar argumentos para el histograma 1D
        histSize[0]= 256;
        hranges[0]= 0.0;
        hranges[1]= 255.0;
        ranges[0]= hranges;
        channels[0]= 0; // por defecto,canal 0
    }


    // Calcular el histograma 1D.
    cv::MatND getHistogram(const cv::Mat &image) {

        cv::MatND hist;

        // Calcular histograma
        cv::calcHist(&image,
            1,   // histograma de solo una imagen
            channels, // el canal usado
            cv::Mat(), // sbinin Mask
            hist,  // el histograma resultante
            1,   // este es un histograma de 1 dimension
            histSize, // numero de contenedores en el histograma
            ranges  // rango de valores de píxeles
        );

        return hist;
    }



    // Calcula el histograma 1D y devuelve una imagen de ella.
    cv::Mat getHistogramImage(const cv::Mat &image){

        // Calcular histograma
        cv::MatND hist= getHistogram(image);

        // Obtener los contenedores min y max
        double maxVal=0;
        double minVal=0;
        cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);

        // Imagen en la que se mostrará el histograma
        cv::Mat histImg(histSize[0], histSize[0], CV_8U,cv::Scalar(255));

        // establecer el punto más alto como 90% of nbins
        int hpt = static_cast<int>(0.9*histSize[0]);

        // dibujar lineas verticales por cada contenedor
        for( int h = 0; h < histSize[0]; h++ ) {

            float binVal = hist.at<float>(h);
            int intensity = static_cast<int>(binVal*hpt/maxVal);
            cv::line(histImg,cv::Point(h,histSize[0]),cv::Point(h,histSize[0]-intensity),cv::Scalar::all(0));
        }

        return histImg;
    }


};
 #endif


main.cpp

#include <iostream>
using namespace std;

#include "cv.h"
#include "highgui.h"
#include "histogram.h"

int main()
{
    // Leer imagen
    cv::Mat image= cv::imread("/home/shellcode/Imágenes/perro.jpg",0);
    if (!image.data)
        return 0;

    // Mostrar la imagen
    cv::namedWindow("Image");
    cv::imshow("Image",image);

    // Objeto histograma
    Histogram1D h;

    // Calcular el histograma
    cv::MatND histo= h.getHistogram(image);

    // Loop sobre cada contenedor del histograma
    for (int i=0; i<256; i++)
        cout << "Value " << i << " = " << histo.at<float>(i) << endl;

    // Mostrar el histograma como una imagen
    cv::namedWindow("Histogram");
    cv::imshow("Histogram",h.getHistogramImage(image));

    cv::waitKey();
    return 0;
}


Resultado


sábado, 18 de abril de 2015

Reducción de colores - Manipulación de pixeles con Opencv




Muchas veces se necesita analizar una imagen pixel por pixel, considerando la cantidad de pixeles
de la imagen, esto puede ser no tan eficiente, por ello hay varias formas de implementar un bucle de scaneo de imagen.
Las imagenes estan compuestas por 3 canales de píxeles ( Rojo, verde, azul) cada uno de estos valores es un 8bit unsigned char, el total de colores es entonces 256x256x256, lo que es cerca de 16 millones de colores, entonces para reducir la complejidad del análisis, usualmente se reduce la cantidad de colores.

Una forma sencilla de lograr este objetivo es simplemente subdividir el espacio RGB en cubos de igual tamaño. Por ejemplo, si se reduce el número de colores en cada dimensión de 8, entonces usted obtendría un total de 32x32x32 colores.
Cada color de la imagen original, entonces se asigna un nuevo valor de color en la imagen de color reducido que corresponde al valor en el centro del cubo a la que pertenece.



Resultado


Alterar color de pixeles - Manipulación de Pixeles con Opencv




Tomando como base el proyecto anterior, modificamos solo el fichero main.cpp
Lo que haremos ahora sera manipular los pixeles, de tal forma que tomaremos una imagen e introduciremos puntos blancos en la imagen en puntos aleatorios, el código es el siguiente.



Notar que hay una condicional if que verifica el número de canales, esto es para saber que tipo de imagen tenemos ya que si la imagen tiene 1 canal (8-bit) solo se asigna el valor 255 en las posiciones a,b
image.at<uchar>(a,b)= 255;

Pero en el caso que tenga 3 canales ( imagen a color ) se tiene que modificar cada uno de ellos
haciendo uso del código del else-if


      image.at<Vec3b>(a,b)[0]= 255;
      image.at<Vec3b>(a,b)[1]= 255;
      image.at<Vec3b>(a,b)[2]= 255;

Resultado




El resto de código ya es conocido, revisar la entrada anterior
Mostrar imágen con Opencv + Qt

Mostrar imágen con Opencv + Qt



Bueno, lo primero es tener instalado Qt y Opencv, una vez hecho eso comenzamos por abrir el Qt Creator.

Damos File > New File or Project y se nos deberá abrir una ventana nos ubicamos en Aplication > Qt Console Application y damos click en el botón Choose...



En esa ventana lo que hacemos será colocar el nombre de la aplicación y elegimos la ubicación de nuestro proyecto, una vez hecho eso damos click en Next



Click en Next





Click en Finish 

Una vez hecho esto vamos a nuestro archivo .pro, en mi caso es holaopencv.pro por que así nombre a mi proyecto y agregamos lo siguiente justo antes de sources


INCLUDEPATH += /usr/local/include/opencv
LIBS += -L/usr/local/lib -lopencv_calib3d -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_highgui -lopencv_imgproc -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab




nos queda algo así.
luego de eso ya podemos incluir las librerías y se activa el autocompletado en qt.



Ponemos el siguiente código para probar que todo esté correcto


Si todo salió bien, deberíamos poder visualizar la imagen que hemos cargado, lo que significa que ya tenemos Opencv preparado para probar su potencial.

Explicación 

namedWindow(nombreVentana)  : Sirve para crear una ventana


Mat : Se utiliza para almacenar vectores o matrices
imread(nombreimagen) : sirve para leer una imagen recibiendo su ubicación
imshow(nombreVentana,imagen) : sirve para mostrar la imagen, recibe como parámetros el nombre de una ventana ( en donde se mostrará) y la imagen.
waitKey(num) : Mostrar por una cantidad específica de mili segundos ( 0 = tiempo infinito ) o hasta que se presione una tecla.