lunes, 4 de abril de 2016

Esta vez intentaremos detectar un objeto basándonos en su color, esta técnico nos servirá para detectar objetos de un color uniforme, veremos cómo extraer las coordenadas en las que se encuentre el color que deseamos detectar y como resaltar el objeto encontrado.

Lo primero que haremos será cambiar el color space de BGR a HSV, de este modo podemos establecer un filtro para obtener solo aquellas secciones de la imagen cuyo color se encuentre en el rango de color indicado, en HSV es más fácil establecer este rango.

rgb-hsv opencv
Realizar la conversión es fácil, usamos la función cvtColor(src, dst, CV_BGR2HSV) indicamos la imagen fuente, destino y el tipo de conversión que puede ser: COLOR_BGR2HSV, COLOR_RGB2HSV, COLOR_HSV2BGR, COLOR_HSV2RGB.

Para filtrar solo aquellos colores que se encuentren en el rango indicado usaremos la función inRange, para este ejemplo filtraremos el color azul, por lo que los rangos superior e inferior estarán definidos de la siguiente manera: inferior { Scalar(110, 50, 50) }, superior { Scalar(130, 255, 255) } en HSV color space.

// obtener frame de la web cam
cap >> img;

// convertir imagen RGB a HSV 
cvtColor(img, hsv, CV_BGR2HSV);

// aplicar filtro para color deseado
inRange(hsv, Scalar(110, 50, 50), Scalar(130, 255, 255), binary);

// aplicar tranformaciones morfologicas (extrae la region de interes)
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
erode(binary, binary, element);
dilate(binary, binary, element);

Este es el resultado de filtrar el color azul con la función inRange, obtenemos una imagen binaria donde el color blanco representa las áreas que contienen el color filtrado.

range color hsv
Para descartar aquellos segmentos no deseados usaremos las transformaciones morfológicas erode y dilate, los configuramos para buscar elementos rectangulares (MORPH_RECT) en nuestra imagen binaria, MORPH_ELLIPSE para figuras circulares.

erode dilate opencv
En este punto lo siguiente que debemos hacer es encontrar las coordenadas donde se encuentra nuestra región de interés, OpenCV cuenta con funciones de búsqueda de contornos que utilizaremos para este propósito, findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE), binary es la imagen binaria que creamos anteriormente, contours es la variable tipo vector<vector<Point>> donde se almacenaran los contornos encontrados, CV_RETR_EXTERNAL indica que solo necesitamos los contornos externos.

// buscar contornos en la imagen binaria
vector< vector<Point> > contours;
findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

// dibujar todos los contornos encontrados
drawContours(binary, contours, -1, Scalar(255), CV_FILLED);

Para finalizar utilizaremos la información obtenida de los contornos para dibujar un rectángulo sobre la imagen original y marcar el color seleccionado, agregamos también el texto con las coordenadas correspondientes, estas coordenadas las obtenemos con la función Rect r = boundingRect(contour);, la función rectangle y putText dibujan el rectángulo y el texto, las hemos visto en tutoriales anteriores.

// dibujar rectangulo y texto con coordenadas (x, y)
for (vector<Point> contour : contours) {
    Rect r = boundingRect(contour);
    rectangle(img, r.tl(), r.br(), CV_RGB(255, 0, 0), 2, CV_AA, 0);

    Point center(r.x + (r.width / 2), r.y + (r.height / 2));

    ostringstream str;
    str << center.x << "," << center.y;

    putText(img, str.str(), center, FONT_HERSHEY_COMPLEX_SMALL, 0.60, CV_RGB(0, 255, 0), 1, CV_AA);
}

Finalmente tenemos el siguiente resultado:

opencv deteccion de objeto por color
GitHub: Seguimiento de Objeto por Color

2 comentarios :

  1. Hola. Lo acabo de ejecutar. Mi computadora tiene cámara y conectó directamente (Apple iMac). Me estoy divirtiendo tirando una botellita azul que tengo en la mano al aire. Genial. Muchas gracias.

    ResponderEliminar
  2. Saludos apenas me estoy familiarizando con el uso de POO en c++ y pues aprendiendo a usar opencv ...gracias por el curso; Con el se acelera el aprendizaje.

    ResponderEliminar