miércoles, 15 de diciembre de 2010

Mi paint

Como ya tengo los dedales calibrados, los sigue bien y esas cosas ahora hay que ponerlos en algo útil, en este caso me he hecho una aplicación que retoca las imágenes. Se pasa una imagen por parámetro y esta se muestra en una ventana, poniendo un pequeño menú en el lado derecho.


En esta captura se observa que el filtro de partículas reconoce donde está cada uno de los dedos. Y en mi aplicación a la izquierda se ve una equis donde se ha reconocido el dedo rojo, que es el puntero. El azul no aparece porque solo se activa con una opción del menú, y el amarillo tampoco se ve porque solo se muestra cuando está encima del menú.

A continuación pongo unas capturas con algunas opciones del menú:

Filtro: cvThreshold(imagen, copia ,100,255, CV_THRESH_TOZERO_INV)




Filtro: cvThreshold(imagen, igauss,100,255, CV_THRESH_TRUNC)



Filtro: cvThreshold(imagen, copia,100, 255,1)

¿Qué he estado haciendo?

Durante todo este tiempo lo que he hecho es trabajar en el mundo real, con los objetos que me interesan realmente. Los dedales que voy a usar definitivamente son estos:



Como se puede apreciar están el rojo, azul y amarillo, con estos he realizado un calibrado de cada uno de ellos.

Para realizar el calibrado primero he situado una ventana donde hay que poner el dedal, y luego se muestra un cuadrado donde se ve el tamaño que recoge el calibrado del objeto en cuestión. Y para que quede más bonito he puesto al lado el umbralizado de la imagen con ese calibrado.



miércoles, 3 de noviembre de 2010

Mis clases

Para hacer el calibrado he tenido que crear clases nuevas y retocar clases que tenía anterior mente. El esquema general ahora mismo es el siguiente:


Y las diferentes clases que tengo son:


En esta clase se almacenan los umbrales que puede coger cada color en RGB. Tengo tres variables, una para cada canal y varias funciones para escribir los valores y para recuperarlos.



Esta clase se dedica a hacer el vector de pesos acumulado, que expliqué anteriormente, y luego selecciona los candidatos que se reproducirán después.


La clase rectángulo ha quedado finalmente así:

  • setID: establece el ID de la partícula.
  • setColor: establece el color de la partícula.
  • setEsquinaIA: establece la esquina superior izquierda.
  • setEsquinaDB: establece la esquina inferior derecha.
  • setAlto: establecida la esquinaIA, calcula la Y de la otra esquina según el alto.
  • setAncho: establecida la esquinaIA, calcula la X de la otra esquina según el ancho.
  • setPeso: establece el peso.
  • getEsquinaIA: devuelve la esquina superior izquierda de la partícula.
  • getEsquinaDB: devuelve la esquina inferior derecha de la partícula.
  • getColor: devuelve el color de la patícula.
  • getPeso: devuelve el peso de la partícula.
  • getID: devuelve el ID de la patícula.
  • dibujar: dibuja la partícula en la imagen que se pasa por parámetro.
  • dispersar: mueve a la partícula de forma aleatoria tanto movimiento como se pasa por parámetro.
  • damePosicion: devuelve el punto central de la partícula.
  • dameAlto: devuelve el alto de la partícula.
  • dameAncho: devuelve el ancho de la partícula.
  • calcularPeso: calcula el peso de la partícula. Se le pasa por parámetro la imagen ya umbralizada, de tal forma que los píxeles importantes están en 255, lo que hace es sumar cuántos de esos píxeles están dentro de la partícula.
  • generarParticula: genera las partículas de forma aleatoria por la imagen, por eso se le pasa la imagen (para saber los bordes), el color de la partícula y alto y ancho que se quiere que tenga.


Esta clase MiImagen es que la que utilizo para tratar la imagen que me pasan. Contiene a la clase umbrales, para saber los umbrales que hay que usar en el umbralizado. También contiene la imagen a la que se le resta el fondo (sinFondo) y la máscara que se obtiene de ésta imagen. A parte tiene el atributo imagen que será donde se guardará la imagen umbralizada. Como se ve hay diferentes funciones de umbralizado para seleccionar cada color. Y por último hay una función para quitar ruido que se aplica sobre la imagen umbralizada.


Los atributos de esta clase son:
  • dedo: es un vector de rectángulos, estas son las partículas que vamos a general para el filtro.
  • color: color que tendrá cada partícula.
  • ancho: ancho de las partículas.
  • alto: alto de las partículas.
  • umbralizado: según el valor se usará un umbralizado.
  • des: desplazamiento de la ventana para calibrar.
  • calib: objeto de la clase calibrado.
  • dibujado: objeto de la clase miImagen.
  • noDibujar: puntero a la imagen principal sobre la que se harán las operaciones.
A continuación explicaré cada una de las funciones:
  • setColor: establece el color que tendrán todas las partículas.
  • setUmbralizado: establece el valor de umbralizado.
  • setDesplazamiento: establece el desplazamiento de la ventana a calibrar.
  • estimado: de todas las partículas que se tienen devolverá el resultado más óptimo, como solo va a haber un dedo de cada color solo puede haber un resultado más óptimo.
  • calcularPesos: calcula los pesos de todas las partículas.
  • dispersar: dispersa todas las partículas en la distancia que se indica.
  • generarAleatorios: genera todas las partículas de forma aleatoria.
  • dibujarCandidatos: una vez calculados los pesos de todas las partículas dibuja en la imagen las partículas que sean candidatas a ser el mejor estimado.
  • nuevosCandidatos: genera los nuevos candidatos que se han elegido en la ruleta.
  • run: función principal que realiza las llamadas correspondientes para el filtro de partículas.
  • seleccionUmbralizado: en función del valor selecciona el umbralizado de un color sobre la imagen.
  • calibrarColor: realiza la calibración del color.



Y esta última clase es la que realiza el calibrado de los colores. Los atributos que tiene son:
  • Ventana: es el rectángulo donde se pondrá el objeto a calibrar.
  • imagen: puntero a objeto miImagen.
  • fondo: imagen de fondo.
  • alto: alto del objeto a seguir.
  • ancho: ancho del objeto a seguir.
Y las funciones que tiene son las siguientes:
  • setImagen: establece el puntero a MiImagen.
  • setVentana: establece la ventana.
  • setFondo: establece el fondo.
  • setAncho: establece el ancho del objeto calibrado.
  • setAlto: establece el alto del objeto calibrado.
  • getAncho: devuelve el ancho del objeto calibrado.
  • getAlto: devuelve el alto del objeto calibrado.
  • calibrar: realiza la calibración del objeto.
  • quitarRuidoMascara: quita el ruido de la máscara.
  • valoresRojo: establece los valores umbral para el color rojo.
  • valoresAzul: establece los valores umbral para el color azul.
  • valoresVerde: establece los valores umbral para el color verde.
  • valoresAmarillo: establece los valores umbral para el color amarillo.
  • quitarFondo: resta a la imagen recogida el fondo.
  • hacerMascara: realiza la máscara de la imagen sin fondo.
  • seleccionValorColor: selecciona que color es del que se quieren coger los valores umbrales.
  • cogerLado: coge del objeto el ancho y alto.

Calibrado

Lo primero que hay que hacer es calibrar los colores que se van a usar, porque ya se sabe que puede cambiar la luz y eso hace que los valores también varíen.

Para ello tengo una clase que se encarga del calibrado de cada color, de la siguiente forma:

- Resta el fondo a la imagen actual.
- Con la nueva imagen hace una máscara, donde pone en 255 los píxeles que han cambiado, esto quiere decir que ahí estará mi objeto a reconocer. Esta máscara no distingue ningún color, sino que junta todos los colores.
- Usando la máscara miro los umbrales del color (en cada caso para el que me es útil en ese momento). Y con ello almaceno los valores máximos y mínimos que tiene mi objeto.
- Recojo el tamaño del objeto, ya que dependerá a la distancia a la que se ponga, pero ejecutando el programa estará a la misma distancia siempre. Esto sirve para ajustar el tamaño de las partículas a lanzar.

Y con todo esto recogido ya puedo usar el filtro de partículas.

lunes, 25 de octubre de 2010

Recogiendo umbrales

Como en el mundo real las cosas son variables lo que estoy haciendo ahora es recoger los umbrales entre los que está cada color.

Para ello hago varios pasos:

Paso 1:
Hago una resta de la imagen actual con el fondo (el fondo ahora es una imagen que he tomado, porque trabajo en el semi mundo, pero luego será el primer frame que se coja de la cámara). Con esta operación lo que consigo es crear una máscara donde los píxeles que han cambiado serán los que tengan mi objeto a buscar.

Paso 2:
Consultando en la máscara, miro en los píxeles que son diferentes los valores que hay en cada canal. Tengo unos umbrales muy genéricos para reconocer cada color, con esta operación lo que hago es ajustar esos umbrales al momento.

Paso 3:
Aplico el umbralizado del color que quiero con los umbrales que he obtenido previamente.


Y con esto, tan bonito y sencillo, consigo hacer la calibración para cada color. Lo siguiente que hay que hacer es juntar esta calibración con el filtro de partículas. Un trabajo de chinos, pero se hará lo que se pueda.

jueves, 21 de octubre de 2010

Acercándose a la realidad

Durante todo este tiempo he estado trabajando con "un mundo ideal", donde las cosas a seguir eran cuadratitos perfectos, con su color bien definido. Es hora de enfrentarse a la realidad, pero no mucho porque da miedito aun.

Así que me he creado un mundo semi-ideal. Ahora mismo en lo que estoy trabajando es en recoger en el vídeo los parámetros que tendrá cada color que voy a seguir. Cuando todo esté bien montado tendré un dedal de cada color, pero hasta entonces tengo que coger lo que encuentro más a mano que son mis bolis de colores (y muchos me llamaron loca cuando los compré, juas).



Como se puede observar cada la tapa de cada boli es del color que quiero que sean los dedales. Y como estoy en un cuasi mundo real voy a trabajar con un fondo fijo.

La primera parte es dividir la pantalla en cuatro zonas diferentes que será donde reconoceré cada uno de los colores.



Y una vez que tengo esas zonas en cada uno de los cuadrados tengo que poner el color que quiero buscar.







Pues con esto tengo ya preparado mi mundo para poder hacer la nueva funcionalidad, pero como ya he dicho que es un cuasi mundo ahora vuelvo trabajar con imágenes fijas para sacar cada color, porque hay que ir pasito a pasito, luego ya cuando tenga el calor suficiente (y el algoritmo funcional) aplicaré el reconocimiento de los colores sobre el vídeo.

Y ya como último paso será atreverme a quitar el fondo, pero para eso aun queda mucho código entre medias.

miércoles, 20 de octubre de 2010

Arreglado

Para solucionar el error de ayer se ha tenido que desinstalar el opencv 2.1 y poner la versión 2.0, después se han instalado los drivers de la cámara, y usado la cámara:




Porque es la única (de las que tenemos) que acepta el formato de entrada en opencv.

Y por último poner cvWaitKey(2);


Con esto ya podemos acceder a la webcam, así que ahora toca trabajar con la imagen que se recoge.

martes, 19 de octubre de 2010

Problemas

Llegados a este punto he descubierto que tengo un problema.

He conectado una webcam y he hecho un programilla simple que lo único que hace es visualizar en una pantalla lo que captura la webcam. Como don Murphy está presente cuando menos lo requieres me ha salido el siguiente error:

HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV


Así que hay que buscar una solución para ello, ¿cuál? Pues la más sencilla es volver a la versión anterior de opencv, la 2.0, que se sabe que no da problemas.

Video del filtro

Antes de poner el vídeo pongo una captura de los diferentes umbralizados que tengo. En la primera imagen se observan dónde se encuentra cada uno de los objetos. En la imagen de abajo están los diferentes umbralizados que se hace a cada objeto de cada color. Como se puede ver solo se encuentra en blanco los píxeles que nos han interesado de cada uno.





Y para ver que esto realmente funciona dejo el seguimiento de los objetos durante todo el vídeo.

Filtro conseguido

El último paso que he tenido que realizar es juntar todo.

Una de las cosas que he tenido que añadir es que si en algún momento no se encuentra ninguna partícula con peso hay que volver a lanzar de forma aleatoria las partículas. Esto en el vídeo que me he creado no es muy útil ya que no desaparecen los elementos a seguir, pero en lo que voy a necesitar si pasará que desaparezca algún elemento y por lo tanto tenga que reiniciarlo de nuevo.

Otra de las cosas que he tenido que cambiar son los umbrales para hacer la umbralización, pues antes estaba trabajando en un mundo perfecto y por lo tanto los colores estaban bien definidos. Por ejemplo tenía que para el rojo necesitaba que el canal de rojo estuviera en 255 y el verde y el azul en cero ambos, así que he tenido que darle un poco más de margen, para el rojo entre 240 y 255 y para los otros dos que sean menos de 10. Los mismos cambios he hecho para el umbralizado en verde, azul y amarillo. Y con este último cambio ya se puede ver cómo funciona el filtro.

Dejo constancia que esto funciona con unas capturas de pantalla, primero de cada uno de los colores por separado y finalmente todo junto. Como se ve en la imagen el cuadrado consigue encontrar cada elemento perfectamente.












Y como estas cosas quedan mucho más bonitas cuando se ve cómo lo va haciendo por todo el vídeo ahora voy a aprender a grabar vídeo con opencv, para poder compartir con el mundo mi gran trabajo, juas.

viernes, 15 de octubre de 2010

Creando un vídeo personal

Como tengo que trabajar en mi mundo abstracto lo siguiente que he hecho ha sido crearme un vídeo adaptado para mi caso.

Para ello hemos usado el programa videosyn, al cual hay que ponerle el tamaño de la imagen del vídeo, los frames que tiene y los objetos. Luego a cada objeto se le define la altura, anchura, color y recorrido que realiza.

Como me interesa me he creado cuatro objetos, cada uno de ellos de un color (rojo, azul, verde y amarillo), y luego les he puesto a moverse por ahí por la pantalla.

El resultado es este vídeo:



Ahora me dedicaré a toquetearlo para encontrar dónde está cada uno de los cuadrados y a seguirlo.

jueves, 14 de octubre de 2010

Abriendo vídeo

Ahora que ya está todo más o menos hecho con las imágenes quietas es hora de dar una vuelta más, o como dirían en el circo, ¡aun más difícil!

Se trata de abrir un vídeo y hacer todo lo que hecho en las imágenes estáticas, pero como hay que empezar por el principio lo primero es abrir el vídeo.

Para ello he investigado que hay un objeto llamado cvCapture, donde se puede meter el vídeo (wuajaja). Para meter el vídeo en ese objeto uso cvCreateFileCapture(dirección de mi vídeo).

Luego solo tengo que crearme una imagen como las he estado manejando hasta ahora (IplImage), y meter frame a frame el vídeo en ella con cvQueryFrame.

¡Y ya está!

A partir de ahí solo tengo que ir trabajando con cada frame e ir aplicando mis cosillas para sacar lo que yo quiero. Fácil, sencillo y para toda la familia.

miércoles, 13 de octubre de 2010

Ruleta

Llegado a este punto me toca explicar el algoritmo de la ruleta.

Partimos de un vector de partículas, donde cada una tiene su peso, lo que queremos conseguir ahora es que las partículas que son más óptimas puedan tener mayor descendencia, y las que no nos interesan no se reproduzcan. Para conseguir esto se usa la ruleta, cuyo funcionamiento es el siguiente.

Se hace un vector con el mismo número de elementos que las partículas que tenemos, en este vector se pondrá el peso acumulado, de tal forma que si la primera tiene peso 5 y la segunda peso 10, el vector nuevo tendrá en el primer elemento un 5 y en el segundo 15, pues se repite para todos los elementos hasta llegar al final.

Después de esto se "lanzan" números de forma aleatoria, teniendo como límite el último elemento de nuestro nuevo vector. Después se mira en cada número a qué elemento corresponde y será ese el nuevo elemento que se propague.

De esta manera lo que se consigue es que las partículas con mayor peso tengan más descendencia, y las que no tengan ningún peso no se sigan propagando.

Y como la explicación me ha quedado tan chapucera, pero yo me entiendo, dejo un dibujo de una ruleta para que al menos parezca bonito.

viernes, 8 de octubre de 2010

Clases

Llegado a este punto necesito hacer una pequeña recopilación de las clases que tengo ahora mismo y cómo funcionan cada una de ellas. Para poder ponerlo todo más bonito y ordenadito he usado el programa umbrello, de momento solo para poner en cada clase qué atributos tiene y qué funciones.



Esta clase MiImagen es que la que utilizo para tratar la imagen que me pasan. Tiene un atributo imagen que es donde se guarda el umbralizado que se realiza a la clase principal. Como se ve hay diferentes funciones de umbralizado para seleccionar cada color. Y por último hay una función para quitar ruido que se aplica sobre la imagen umbralizada.


Esta clase Rectángulo es la más bonita de todas, como se puede ver es la que tiene más funciones. Con esta clase es con la que simulo mis partículas. Cada rectángulo se define por la esquina superior izquierda (esquinaIA), esquina inferior derecha (esquinaDB), color de la partícula y peso.
A continuación explicaré cada una de las funciones:

  • setID: establece el ID de la partícula.
  • setColor: establece el color de la partícula.
  • getEsquinaIA: devuelve la esquina superior izquierda de la partícula.
  • getEsquinaDB: devuelve la esquina inferior derecha de la partícula.
  • getColor: devuelve el color de la patícula.
  • getPeso: devuelve el peso de la partícula.
  • getID: devuelve el ID de la patícula.
  • dibujar: dibuja la partícula en la imagen que se pasa por parámetro.
  • dispersar: mueve a la partícula de forma aleatoria tanto movimiento como se pasa por parámetro.
  • damePosicion: devuelve el punto central de la partícula.
  • dameAlto: devuelve el alto de la partícula.
  • dameAncho: devuelve el ancho de la partícula.
  • calcularPeso: calcula el peso de la partícula. Se le pasa por parámetro la imagen ya umbralizada, de tal forma que los píxeles importantes están en 255, lo que hace es sumar cuántos de esos píxeles están dentro de la partícula.
  • generarParticula: genera las partículas de forma aleatoria por la imagen, por eso se le pasa la imagen (para saber los bordes), el color de la partícula y el lado que se quiere que tenga.


La clase dedos es la que va a realizar nuestra búsqueda. Los atributos que tienen son un vector de partículas, que se generarán al crear el dedo, el número de partículas que se harán se pasa por parámetro al inicializar el dedo, así se reserva al principio del programa la memoria que se requiera en cada caso. Los atributos color y lado se pasarán también al inicializar.
A continuación explicaré cada una de las funciones:
  • setColor: establece el color que tendrán todas las partículas.
  • setLado: establece el lado que tendrán todas las partículas.
  • estimado: de todas las partículas que se tienen devolverá el resultado más óptimo, como solo va a haber un dedo de cada color solo puede haber un resultado más óptimo.
  • calcularPesos: calcula los pesos de todas las partículas.
  • dispersar: dispersa todas las partículas en la distancia que se indica.
  • generarAleatorios: genera todas las partículas de forma aleatoria.
  • dibujarCandidatos: una vez calculados los pesos de todas las partículas dibuja en la imagen las partículas que sean candidatas a ser el mejor estimado.

Actualmente las clases están de esta forma, aunque seguramente habrá que añadir otras más para poder seguir implementando el filtro. Ahora voy a dedicarme a implementar la clase ruleta, cuya funcionalidad explicaré en la siguiente entrada.

jueves, 7 de octubre de 2010

Reconociendo colores

Como la idea final del proyecto es que se reconozcan cuatro colores diferentes, que vana ser cada dedo, he realizado una imagen con los cuatro colores que me interesan:



A esa imagen le aplico un filtro, para umbralizar el color con el que me quiero quedar en cada paso. Después lanzo partículas de forma aleatoria por toda la imagen, y de todas las partículas lanzadas me quedo con las que tienen un peso mayor a 300. Quedando el siguiente resultado:









Ya tengo cómo trabajar con cada color en cada paso, pero claro, como esto ha empezado a complicarse un poco lo mejor es tener un esquema claro de todas las clases que tengo ahora mismo para saber qué funciones tiene cada una. Pero eso es algo que me guardo para la siguiente entrada.

miércoles, 6 de octubre de 2010

Vectores

He visto que para poder tener todo más ordenadito necesito usar la clase vector de c++, porque es lo mismo que yo haría para poder usar memoria dinámica y ya se sabe el dicho "si ya lo ha hecho otro, trabajo que me ahorro".

La clase vector sirve para poder tener listas dinámicas, de esta forma no tengo que andar comiéndome la cabeza con la reserva de memoria, la liberación o acceso a memoria que está usada.

Las diferentes funciones de esta clase que me van a interesar son:


size() -> dice el tamaño que tiene el vector.
operator[] -> accede a un elemento determinado.
at ->accede a un elemento determinado.
push_back -> añade un elemento al final del vector.
clear() -> libera la memoria usada por el vector.

martes, 5 de octubre de 2010

Lanzando partículas

Poco a poco voy haciendo un acercamiento al filtro de partículas para poder seguir los dedos.

Para ello el primer paso es generar partículas de forma aleatoria sobre una imagen. Las partículas, son los rectángulos que había creado antes, de la clase Rectángulo.

Lanzando un número suficiente de partículas se cubre la imagen que queremos.



Una vez lanzadas las partículas por toda la imagen, lo que interesa son las partículas que estén sobre la parte que nos interesa. Para seleccionar la parte que nos interesa usamos el umbralizado para el rojo como ya he puesto en una entrada anterior.

Una vez que tengo la imagen umbralizada lo que hago es trabajar con ella con las partículas. La forma de seleccionar la que me interesa es añadirle un peso a cada partícula, es decir, el peso en este caso es la cantidad de píxeles que me interesan están dentro de esa partícula. De ésta forma se puede ver cómo seleccionamos las partículas que nos interesan, en la imagen a continuación vemos que en amarillo están las de interés y en azul las que no.



Para que se observe mejor solo pintaré en la imagen las partículas que me interesan.



Una vez conseguido esto, voy a por el siguiente paso del filtro de partículas.

lunes, 4 de octubre de 2010

Simulando movimiento

Para poder seguir el movimiento de mis dedos por la pantalla necesito poder hacer que los rectángulos o partículas se muevan de forma aleatoria desde un punto en el que estén inicialmente una distancia que yo elija, me he creado en la clase rectángulo una función dispersar, a la que se le pasa el movimiento que se quiere conseguir.

void dispersar(int mov);


Para probar esta función me creo una partícula y hago que se disperse con diferentes valores, teniendo como resultado esto:

viernes, 1 de octubre de 2010

Clase Mano

Ahora he hecho una nueva clase, que contiene varios objetos de la clase anterior, así que para manejarlo me he creado las diferentes funciones:


void setRectangulo(Rectangulo r);
void restarRectangulo();

CvPoint posicionRectangulo (int id);
IplImage* dibujaRectangulo(IplImage* img);


Las funciones lo que hacen es añadir rectángulos en mi clase (hasta un límite de cuatro), también puede quitar uno que se haya añadido antes, la posición de un determinado rectángulo y por último dibujar todos los rectángulos.


jueves, 30 de septiembre de 2010

Clase rectángulo

Para poder tener todo un poco más ordenado me he creado una clase rectángulo.

Mis rectángulos se definen por la esquina de arriba a la izquierda, la esquina de abajo a la derecha, el color y un identificador.
Al crear un rectángulo se le pasan la posición de las esquinas, y el color y el identificador son opcionales, pudiendo ponerlos en otro momento. Las funciones para manejar estos atributos son las siguientes:

void setID(int i);
void setColor(CvScalar c);

CvPoint getEsquinaIA();
CvPoint getEsquinaDB();
CvScalar getColor();
int getID();



Después, como habrá que dibujar los rectángulos también me he puesto una función para que los dibuje:

IplImage* dibujar(IplImage* img);


Y por último, unas funciones para que me digan la posición del rectángulo (el punto central), la altura y la anchura del mismo:

CvPoint damePosicion ();
int dameAlto();
int dameAncho();


Para ver que funcionaba me he puesto a probar las diferentes funcionalidades en una foto, haciendo dos rectángulos.

martes, 28 de septiembre de 2010

Difuminando y eliminando ruido

He descubierto la función cvSmooth, con la que puedo aplicar diferentes tipos de transformaciones en la imagen, como estudié visión hace ya tiempo y me sonaba que el filtro gaussiano lo que hacía era difuminar la imagen y eliminar así el ruido he probado a ver que pasaba.




Como se puede ver, mi gozo en un pozo, porque la idea era que difuminando un poco la imagen pudiera eliminar el ruido, pero con esto no lo elimino, sino que hago que intente pasar desapercibido, que si mi aplicación tuviera un poco de miopía daría el pego, pero creo que no es el caso (aun lo estoy estudiando).


Así que he experimentado un poco más dentro de esa función y he encontrado el filtro "Median blur", que aplicado a mi imagen consigo esto:




¡Tachán! Es más parecido a lo que ando buscando, aunque hay ciertos puntos de ruidos que no elimina (nada es perfecto, por ahora).

Es un buen resultado el obtenido, pero como siempre se quiere más, ahora voy a ponerme a descubrir cómo era eso de disminuir y dilatar los píxeles, que tengo el presentimiento de que eso es lo que estoy buscando.

Añadiendo ruido

Usando la imagen que he obtenido antes de elegir el rojo le he añadido de forma aleatoria puntos con ruido.





Ahora lo que tengo que hacer es usar funciones de opencv para poder quitar ese ruido.

Umbralizando

Después de estar trasteando con ciertas funciones, ahora lo que quiero hacer es seleccionar de una imagen un color determinado, para poder luego trabajar con ello.
El color elegido al azar entre los tres colores importantes es el rojo, así que con una imagen sencilla en la que hay círculos me quedo con los rojos que son los más molones. El resultado es el siguiente:




Como se puede observar ha sido una elección óptima, pero claro, el mundo no es perfecto para estas cosas, así que ahora me dedicaré a meter ruido en la imagen para que sea un poco más real.

viernes, 10 de septiembre de 2010

Acceso por punteros

Esta vez he accedido a la imagen por medio de punteros de la siguiente manera:
v=((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels+k];

De esta forma se accede a todos los pixeles de la imagen uno a uno. Para probarlo la transformación que he hecho a la imagen es restar 125 si el valor del pixel es mayor a 125, y sumar 125 si el valor era menor a 125. El resultado final ha sido:



miércoles, 8 de septiembre de 2010

Negativando

He cogido una imagen y accediendo pixel por pixel con la función cvGet2D, después he mirado el valor del pixel para cambiarlo (si estaba a 0 lo he cambiado a 255 y si tenía 255 a 0), y después he metido los nuevos valores en otra imagen con la función cvSet2D.

Con ello el resultado obtenido es el negativo de una imagen en blanco y negro.




Ahora lo intentaré hacer con punteros.