2-5 -2 Segmentación del color

Bueno ya hemos hecho una segmentación del color, muy bien por nosotros, pero ahora quiero hacerlo en movimiento.

Y grabar el vídeo, y que me haga el cálculo del ángulo y el centro y el área, vamos que por pedir que no quede.

Análisis estructural en movimiento.

Ya hemos visto como sacar un color en concreto, como buscar con una herramienta el color buscado (Pixel.cpp)

Lo que necesitamos es buscar un rango de colores que nos muestre el color buscado, aquí hay un problema importante y es la luz, pero es algo que iremos mejorando.

Vamos a buscar un amarillo

imagen

 

Haciendo uso del programa pixel.cpp y su actualización a pixel_cam.cpp (que permite hacer las pruebas con vídeo), podemos extraer los extremos de los colores buscados.

Todos los pasos a seguir ya los hemos hecho en lo que llevamos de módulo, esto es un ejercicio un nivel más allá.

Pasos a seguir.

1º Obtención de la imagen de la cámara

VideoCapture cap

Lo que nos hace es crear un objeto que leerá directamente la entrada de la imagen por webcam o fichero.

VideoCapture cap(0); //webcam
VideoCaptura cap(fichero.avi);//archivo

 

Ya vimos como para trabajar con vídeo hay que tomar una serie de consideraciones.

int fps = 30; // según nuestra cámara
int wait = 1000/fps ;//tiempo de espera entre frame
bool fin= false; // para salir del bucle
bool stop = false; //Por si queremos parar la imagen
char key =0; //para la captura del teclado.

Trabajando con el vídeo.

 

while (!fin)
{

cap >> img; // nos pone un fotograma dentro de la imagen.
//tomamos el tiempo
//Procesar la imagen
//esperamos no los 1000/30 milisegundos, si no que hay que restar el tiempo empleado, y evitar que sea negativos.
wait = 1000/fps – getTick(flag);
key=waitKey(wait <0 ?1:wait);
switch((char)key)
{
}//control de las teclas

}

 

Procesar la imagen.

Recordamos que findContour, trabaja con imágenes binarias, y que solíamos obtener usando canny o threshold.
Ahora podemos obtener esa imagen con inRange, que nos devuelve una imagen a negro (0), salvo los colores que cumplen la condición, que devuelven (1), y ya tenemos nuestra imagen binaria.

 

inrange

Una vez ya tenemos nuestra imagen binaria ya podemos actuar como lo hacíamos para buscar contornos y sus propiedades.

Las recordamos un poco

inRange –> imagen binaria –> findContours
Bucle para recorrer los contornos.
Approximación a poligonos.
Calcular los momentos (moments)
centro, rectángulo, rectángulo rotado.

deteccion_color

deteccion_inrange

Con esto ya podríamos detectar y tener una posición de los objetos buscados.

Grabar el vídeo.

Igual que se puede abrir un vídeo, podemos grabarlo, para ello está el objeto VideoWriter.

VideoWrite rec (fichero, CV_FOURCC(‘D’,’I’,’V’,’X’),fps, img.size(),color=true);

rec << img ; //Ya está grabada la imagen.

Ahora toca hacer el ejercicio.

 

#include “tools.h”

int main(int argc,char** argv)
{
VideoCapture cap;
//Preparamos el fichero, ya sea para vídeo o para cámara web
argc >1 ? cap.open(argv[1]):cap.open(0);

//Nuestra cámara web/video lo vamos a trabajar a 30 fps

int fps = 30;
int wait = 1000/fps;
bool fin = false;
bool stop = false;
char key = 0;

Mat img ;
Mat imgRange;
//Mat imgKeyPoint;
Scalar minColor (0,0,216);
Scalar maxColor (163,255,255);

vector<vector<Point> > contorno;
vector<Vec4i> jerarquia;

Moments momento;
Point2i centro;
vector<Point> aproximacion;
Rect rectangulo;
RotatedRect rotado;
RotatedRect elipse;
Point2f vertices[4];
Point2f centroMinimo;

cap >> img; // tomamos una primera imagen así podemos ver el espacio para grabar
VideoWriter rec(“Deteccion_color.avi”,CV_FOURCC(‘D’,’I’,’V’,’X’),25,img.size(),true);
VideoWriter recInRange(“Deteccion_inRange.avi”,CV_FOURCC(‘D’,’I’,’V’,’X’),25,img.size(),true);
double flag;

while (!fin)
{
cap >> img;//capturamos una imagen del fichero
flag=getTickCount();//tomamos marca de tiempo
inRange(img,minColor,maxColor,imgRange); //Sacamos el rango del color buscado
blur(imgRange,imgRange,Size(3,3));
//inRange, ya nos devuelve una imagen binaria donde buscar contorno.
findContours(imgRange,contorno,jerarquia,CV_RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
for (size_t s = 0 ; s < contorno.size();s++)
{
drawContours(img,contorno,s,BLUE,1,8,jerarquia,0,Point());//para cada contorno lo dibujamos
approxPolyDP(Mat(contorno[s]),aproximacion,1,true);//Hacemos la aproximación a un poligono
momento= moments(aproximacion,false);//calcular los momentos de la aproxiamación
centro = Point2i(momento.m10/momento.m00,momento.m01/momento.m00);
rectangulo = boundingRect(aproximacion); //enmarcarlo en un rectángulo
rectangle(img,rectangulo,RED,1);
rotado = minAreaRect(aproximacion);//Rectángulo rotado
rotado.points(vertices);//Obtener los vértices
char texto[10];
sprintf(texto,”%.2f”,rotado.angle);
putText(img,texto, Point(40,40),FONT_HERSHEY_SIMPLEX,1,BLUE,2);
for (uint8_t i =0;i<4;i++)
{
line(img,vertices[i],vertices[(i+1)%4],GREEN,1,8);
}

}
imshow(“Rango”,imgRange);
rec << img;
cvtColor(imgRange,imgRange,CV_GRAY2RGB);
recInRange << imgRange;
imshow(“VIDEO”,img);
cout << getTick(flag) << endl;//tiempo empleado en el proceso
wait = 1000/fps -getTick(flag);
key=waitKey(wait<0 ? 1:wait);
switch((char)key)
{
case ‘x’:
case 27:
fin= true;
break;
case ‘ ‘:
stop!=stop;
stop? wait=0:wait=1000/fps;
break;
}
}
}