Uno de los problemas más comunes que nos encontramos a la hora de analizar imágenes obtenidas desde dispositivos de captura es el ruido de compresión, cuantización y de sensibilidad del sensor de captura.
Uno de los métodos existentes para reducir ese ruido es filtrar espacialmente la imagen (suavizado) aunque ello provoque pérdida del detalle de la imagen.
Realizaremos tres ejemplos usando un filtro lineal gausiano (CV_GAUSSIAN) con unos tamaños de 1x9 (filtro de suavizamiento vertical), 9x1 (suavizamiento horizontal) y 9x9 (suavizamiento normal).
La función que realiza el filtro de suavizado de imagen en OpenCV es cvSmooth.
El código fuente del ejemplo es:
El resultado de suavizar horizontalmente la imagen elimina la mayoría del ruido producido por la emisión en el aire de señales de televisión al tiempo que se pierde la definición de las imágenes en forma de columnas verticales.
Tras suavizar verticalmente la imagen se elimina el granulado debido a cuantización y codificación en muchas webcams (observar cómo prácticamente ha desaparecido el ruido en la imagen superior derecha) pero se pierde la definición de las imágenes en forma de filas horizontales (ver cómo prácticamente desaparecen las rayas del jersey).
El mejor resultado de obtiene al filtrar horizontal y verticalmente la imagen, pero al mismo tiempo es cuando se pierde mayor detalle de la imagen.
El resultado obtenido tras ejecutar el código de ejemplo es:
Blog dedicado a CREAR conocimiento sobre robótica, electrónica, proporcionando las herramientas necesarias para que puedas "hacer tú mismo" tu propio robot :)
martes, 4 de enero de 2011
Otro ejemplo de región de interés (ROI) en OpenCV
Para ilustrar mejor el funcionamiento de las regiones de interés (antes de continuar con algoritmos de filtrado de imagen) veremos un último ejemplo sencillo de regiones de interés en el que sólo visualizaremos una línea horizontal de la parte inferior de la imagen (útil para implementar, por ejemplo, algoritmos de robots sigue líneas).
El código del ejemplo es el siguiente:
En este caso lo que hemos hecho ha sido marcar como región de interés (ROI) únicamente la zona inferior de una altura determinada. Al hacerlo estamos diciendo que sólo nos interesa trabajar con esa zona de la imagen, por lo que al mostrar el fotograma sólo veremos la parte inferior seleccionada.
El resultado obtenido (con una altura de 50 puntos de pantalla) es:
El código del ejemplo es el siguiente:
En este caso lo que hemos hecho ha sido marcar como región de interés (ROI) únicamente la zona inferior de una altura determinada. Al hacerlo estamos diciendo que sólo nos interesa trabajar con esa zona de la imagen, por lo que al mostrar el fotograma sólo veremos la parte inferior seleccionada.
El resultado obtenido (con una altura de 50 puntos de pantalla) es:
Etiquetas:
c,
gcc,
opencv,
región de interés,
roi,
visión artificial
domingo, 2 de enero de 2011
Mezclando dos imágenes en una con OpenCV
No existe forma directa de mostrar dos imágenes dentro de una misma ventana usando las funciones ofrecidas por OpenCV, pero podemos hacer uso de la región de interés (ROI - Region Of Interest) para conseguirlo.
Con las regiones de interés podemos definir a qué parte de una imagen destino queremos "pegar" el contenido de una imagen fuente. De esta manera conseguimos "componer" la imagen destino deseada a partir de todas las imágenes fuentes necesarias.
En el siguiente ejemplo obtendremos un fotograma del dispositivo de captura y lo mostraremos a tamaño completo con una versión en miniatura del mismo fotograma en su interior.
Una cosa muy importante a tener cuando trabajamos con fotogramas capturados usando OpenCV es que no debemos modificar la imagen entregada por cvQueryFrame ni podremos reutilizar la imagen obtenida por sucesivos fotogramas capturados (explicaré mejor esto último en sucesivos ejemplos).
Por este motivo la composición se hará en una imagen clonada a partir del fotograma capturado usando la función cvClone. Tras ello definiremos la región de interés en dicha imagen clonada (el área de destino donde "pegaremos" de nuevo la imagen) y usaremos de nuevo la función cvResize para copiar una versión escalada del fotograma dentro de la región deseada.
Es importante recordar que la función cvClone aloja la memoria necesaria para almacenar tanto la cabecera de la imagen como su contenido, de modo que llamadas sucesivas a dicha función sin liberar los recursos previamente provocará que nuestra aplicación esté continuamente aumentando su consumo de memoria, de modo que no debemos olvidarnos de liberar los recursos reservados mediante una llamada a la función cvReleaseImage.
Código fuente del ejemplo:
Explicación en detalle paso por paso:
El resultado obtenido es:
Con las regiones de interés podemos definir a qué parte de una imagen destino queremos "pegar" el contenido de una imagen fuente. De esta manera conseguimos "componer" la imagen destino deseada a partir de todas las imágenes fuentes necesarias.
En el siguiente ejemplo obtendremos un fotograma del dispositivo de captura y lo mostraremos a tamaño completo con una versión en miniatura del mismo fotograma en su interior.
Una cosa muy importante a tener cuando trabajamos con fotogramas capturados usando OpenCV es que no debemos modificar la imagen entregada por cvQueryFrame ni podremos reutilizar la imagen obtenida por sucesivos fotogramas capturados (explicaré mejor esto último en sucesivos ejemplos).
Por este motivo la composición se hará en una imagen clonada a partir del fotograma capturado usando la función cvClone. Tras ello definiremos la región de interés en dicha imagen clonada (el área de destino donde "pegaremos" de nuevo la imagen) y usaremos de nuevo la función cvResize para copiar una versión escalada del fotograma dentro de la región deseada.
Es importante recordar que la función cvClone aloja la memoria necesaria para almacenar tanto la cabecera de la imagen como su contenido, de modo que llamadas sucesivas a dicha función sin liberar los recursos previamente provocará que nuestra aplicación esté continuamente aumentando su consumo de memoria, de modo que no debemos olvidarnos de liberar los recursos reservados mediante una llamada a la función cvReleaseImage.
Código fuente del ejemplo:
Explicación en detalle paso por paso:
- Obtenemos un fotograma del dispositivo de captura en "fotograma".
- Creamos una copia del fotograma en "copia".
- Seleccionamos una zona de la imagen "copia" sobre la que volcaremos una versión escalada (una miniatura) del mismo fotograma.
- Realizamos el escalado de imagen sobre esa zona de interés.
- Deshacemos la selección de zona para que la función cvShowImage no nos muestre únicamente la región de interés (nos aparecería únicamente la zona recién escalada), si no la composición completa (el fotograma en grande junto con la miniatura.
- Tras mostrar la composición realizada en "copia" liberamos la memoria usada.
El resultado obtenido es:
Escalando el tamaño de un fotograma capturado usando OpenCV
Debido a que algunos algoritmos pueden consumir una cantidad excesiva de CPU impidiendo su ejecución en tiempo real (o, al menos, con una frecuencia de 10 veces por segundo), tenemos la opción de reducir el tamaño del fotograma a unas dimensiones que nos permita trabajar con un mayor número de fotogramas por segundo.
Para ello usaremos la función cvResize (escalado de imágenes).
Aquí tenemos un ejemplo en el que mostramos la imagen obtenida del dispositivo de captura, pero escalada al tamaño deseado:
Para ello usaremos la función cvResize (escalado de imágenes).
Aquí tenemos un ejemplo en el que mostramos la imagen obtenida del dispositivo de captura, pero escalada al tamaño deseado:
Limitaciones en la captura de imágenes con OpenCV
Dependiendo del dispositivo de captura usado, la plataforma sobre la que se compile la aplicación (cada API de cada sistema operativo tiene diferentes limitaciones y ventajas) y el dispositivo de captura usado (no todos los dispositivos admiten cualquier resolución), podremos hacer uso de la configuración del alto y ancho de la imagen (resolución) que deseamos obtener del dispositivo de captura.
Esto nos permitirá, sobre todo, ahorrar ancho de banda del bus al que se encuentre conectado el dispositivo, disminuir el uso de CPU para procesar cierto tipo de imágenes (sobre todo si se trata de una cámara que ofrece unas resoluciones muy elevadas), aumentar el número de imágenes por segundo que podemos obtener del dispositivo, etc.
Para conseguirlo deberemos hacer uso de la función cvSetCaptureProperty para modificar los parámetros CV_CAP_PROP_FRAME_WIDTH (ancho) y CV_CAP_PROP_FRAME_HEIGHT (alto).
Podemos ver cómo hacerlo en el siguiente ejemplo:
Nota: La implementación de V4L2 en OpenCV 2.1 parece estar rota bajo Linux, por lo que falla el cambio de resolución. He encontrado parches para hacerlo funcionar de nuevo, pero confío en que lo arreglarán en breve espacio de tiempo.
Esto nos permitirá, sobre todo, ahorrar ancho de banda del bus al que se encuentre conectado el dispositivo, disminuir el uso de CPU para procesar cierto tipo de imágenes (sobre todo si se trata de una cámara que ofrece unas resoluciones muy elevadas), aumentar el número de imágenes por segundo que podemos obtener del dispositivo, etc.
Para conseguirlo deberemos hacer uso de la función cvSetCaptureProperty para modificar los parámetros CV_CAP_PROP_FRAME_WIDTH (ancho) y CV_CAP_PROP_FRAME_HEIGHT (alto).
Podemos ver cómo hacerlo en el siguiente ejemplo:
Nota: La implementación de V4L2 en OpenCV 2.1 parece estar rota bajo Linux, por lo que falla el cambio de resolución. He encontrado parches para hacerlo funcionar de nuevo, pero confío en que lo arreglarán en breve espacio de tiempo.
Suscribirse a:
Entradas (Atom)