martes, 13 de febrero de 2018

Práctica 0: color filter

En esta práctica (https://github.com/JdeRobot/Academy/tree/master/src/color_filter), el objetivo es segmentar algún objeto en los vídeos proporcionados, los cuales se pueden descargar en http://jderobot.org/JdeRobot-Academy#Color_filter. En la práctica, los objetos a segmentar son o una pelota o varias pelotas. Para realizar esta práctica emplearemos la plataforma JdeRobot, el lenguaje Python y la librería OpenCV, y haremos un filtro de color.

Para poder realizar la práctica emplearemos el componente cameraserver de JdeRobot, que nos proporciona las imágenes de un vídeo o las obtenidas por una cámara. Para ejecutar el componente cameraserver ponemos en un terminal lo siguiente:

cameraserver cameraserver_conf.cfg

Para ejecutar nuestro código tenemos que poner en el terminal:

 python2 ./color_filter.py color_filter_conf.yml

1. El primer paso es obtener la imagen proporcionada por cameraserver (en este caso será la del vídeo) mediante input_image = self.camera.getImage(). Este paso ya nos lo proporcionan en la plantilla de la práctica. La imagen de entrada la podemos mostrar en la GUI que se nos proporciona en la práctica. Para ello empleamos la siguiente sentencia:

self.camera.setColorImage(input_image)


 2. Las imágenes proporcionadas por el cameraserver tienen mucho ruido. Por este motivo es recomendable emplear un suavizado para eliminar este ruido. En la solución se ha empleado un filtro Gaussiano.

 gaussian_image = cv2.GaussianBlur(input_image, (5, 5), 0.2)


3. La imagen está en RGB, por lo que hacemos una conversión de espacio de color a HSV para poder reconocer las pelotas en un ambiente de luminosidad variado.

hsv_image = cv2.cvtColor(gaussian_image, cv2.COLOR_RGB2HSV)


4. El siguiente paso es aplicar un filtro de color. Para saber qué valores aplicar para filtrar las pelotas se puede emplear la herramienta color_tuner proporcionada en la práctica. Aplicamos el filtro de color con estos valores mínimo y máximo para el tono, la saturación y la intensidad. Con dicha función obtendremos una imagen umbralizada, donde los objetos deseados aparecerá en blanco y el resto en negro.

image_HSV_filtered = cv2.inRange(hsv_image, value_min_HSV, value_max_HSV)

5. Se emplea la operación morfológica cierre para que se rellenen los huecos que quedan sin filtrar en las pelotas tratando de mejorar el umbralizado obtenido. 

kernel = np.ones((19, 19), np.uint8)

image_HSV_filt_close=cv2.morphologyEx(image_HSV_filtered, cv2.MORPH_CLOSE, kernel) 

self.camera.setThresoldImage(image_HSV_filt_close) 


6. Copiamos la imagen original y la filtrada para no modificarlas:


image_HSV_filtered_Copy = np.copy(image_HSV_filt_close)
input_image_Copy = np.copy(input_image)


7. Se aplica findcontour de OpenCV para detectar el contorno de la zona filtrada.  

_, contours, hierarchy = cv2.findContours(image_HSV_filtered_Copy, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)


8. Se emplea approxPolyDP de OpenCV para aproximar los contornos.

cnt = cv2.approxPolyDP(contours[0], 3, True)


9. Se emplea boundingRect para detectar el rectángulo que se ajusta al contorno detectado.  

x, y, w, h= cv2.boundingRect(cnt)


10. Por último, se pinta un rectángulo alrededor de las zonas detectadas como pelota, así como una circunferencia.


cv2.rectangle(input_image_Copy, (x, y),  (x+w, y+h), (0, 255, 0) ,2)

center = [x + w/2, y + h/2]

cv2.circle(input_image_Copy, (center[0], center[1], h/2, (255, 0, 0), 2)


pelota_roja.avi

Para realizar la detección se han usado los siguientes valores en el filtrado:

value_min_HSV = np.array([110, 195, 144])
value_max_HSV = np.array([180, 255, 255])

Debido a que solamente hay una pelota, me he quedado con el contorno de mayor área. Se puede ver el resultado en el siguiente vídeo.

 


pelotas_roja_azul.avi

En el caso de este vídeo, se han empleado los siguientes valores para el filtrado:

value_min_HSV = np.array([110, 195, 144])
value_max_HSV = np.array([180, 255, 255])
value_min_HSV_blue = np.array([72, 58, 34])
value_max_HSV_blue = np.array([150, 255, 255])

 Al tener dos pelotas de diferentes colores, se ha realizado un filtrado para el rojo y otro para el azul. El resultado se puede ver en el siguiente vídeo.




drone1.mp4

Para este vídeo se han empleado los siguientes valores en el filtrado:

value_min_HSV = np.array([144.55, 135.15, 76.53])
value_max_HSV = np.array([187.5, 245, 255])
value_min_HSV_blue = np.array([110.2, 145.86, 110.515])
value_max_HSV_blue = np.array([150.54, 225, 150.96])

El resultado es el siguiente:



drone2.mp4

En este vídeo se han empleado los siguientes valores en el filtrado:

value_min_HSV = np.array([120, 110, 99])
value_max_HSV = np.array([180, 255, 255])
value_min_HSV_blue = np.array([8, 110, 110])
value_max_HSV_blue = np.array([127, 246, 255])

El resultado es el siguiente: