Sunday, April 18, 2010

Efecto fotocopia en tiempo real

He estado jugando un poco con la librería de visión artificial de Intel, OpenCV. Programé el mismo efecto fotocopia que postie tiempo atrás, pero esta vez aplicandolo al video capturado por la webcam en tiempo real.
Esto no es difícil de lograr, sin embargo es interesante ver los resultados.

Aca el código:


#include <opencv/highgui.h>
#include <opencv/cv.h>

void fotocopia(IplImage *img, int difMax) {
int i,j,difh,difw,indice;
for( i=0 ; i < (img->width-1) ; i++) {
for( j=0 ; j < (img->height-1) ; j++) {
indice = j*img->widthStep + i*img->nChannels;
/*diferencia brillo en pixeles de una misma columna
widthStep es el tamaño de una fila en bytes,
ya que la imagen esta en un arreglo unidimensional.
Al sumar widthStep estamos pasando a la siguiente fila
*/
difh = ( (uchar*)(img->imageData) )[indice] - ( (uchar*)(img->imageData) )[indice+img->widthStep];
if( difh < 0) {
difh = difh * -1;
}

//diferencia brillo en pixeles de una misma fila

difw = ( (uchar*)(img->imageData) )[indice] - ( (uchar*)(img->imageData) )[indice+1];
if( difw < 0) {
difw = difw * -1;
}

//si hay mucha diferencia, es un contorno, hay que pintar el pixel negro
if ( (difh + difw) > difMax) {
( (uchar*)(img->imageData) )[indice] = 0 ;
} else {
( (uchar*)(img->imageData) )[indice] = 255 ;
}
}
}
}

int main() {
CvCapture *cap = cvCreateCameraCapture(0);
IplImage *img;
IplImage *imgGray;
cvNamedWindow("hahaha",CV_WINDOW_AUTOSIZE);
img = cvQueryFrame(cap);
imgGray = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_8U, 1 );
while(1) {
img = cvQueryFrame(cap);
cvCvtColor(img, imgGray, CV_RGB2GRAY);
fotocopia(imgGray,5);
cvShowImage("hahaha",imgGray);
char key = cvWaitKey(40);
if(key == 27)
break;
}
cvReleaseCapture(&cap);
cvReleaseImage(&img);
cvReleaseImage(&imgGray);
cvDestroyWindow("hahaha");
}

Para compilar:

gcc `pkg-config --cflags opencv --libs opencv` fotocopia.c -o fotocopia

Aca un video de cómo se queda el efecto:

Thursday, April 1, 2010

tarjeta de video Intel GMA X4500HD Ubuntu

Problema:

Cuando abría alguna aplicación que hiciera uso de OpenGL esta veía con manchas negras o se pegaba y al ejecutar dmesg me aparecía lo siguiente:

[ 210.430986] [drm:i915_gem_object_pin_and_relocate] *ERROR* Relocation beyond target object bounds: obj f08cb9c0 target 23 delta 4096 size 4096.
[ 210.430992] [drm:i915_gem_execbuffer] *ERROR* Failed to pin buffers -22
[ 210.445817] [drm:i915_gem_object_pin_and_relocate] *ERROR* Relocation beyond target object bounds: obj f0a39180 target 23 delta 4096 size 4096.
[ 210.445827] [drm:i915_gem_execbuffer] *ERROR* Failed to pin buffers -22

....

Usando Ubuntu 9.10 the Karmic Koala con el paquete xserver-xorg-video-intel versión:
2:2.9.1~git-0ubuntu0tormod

Solución :

apt-get install libgl1-mesa-dri
Con lo cual se actualizaron los siguientes paquetes:
libdrm-intel1 a la versión 2.4.15~git-0ubuntu0tormod~jaunty
libgl1-mesa-dri a la versión 7.7.0~git20091114.57f40b18-0ubuntu0sarvatt~jaunty

La solución la encontré aquí.

Thursday, February 18, 2010

Editando imagenes con Octave

Me encanta el filtro fotocopia que trae el Gimp para dejar una foto como un dibujo, me dí cuenta de que es muy intuitivo hacer este efecto en Octave. Para ello sólo hace falta usar la función gradiente que toma una matriz y calcula la diferencia que hay entre dos elementos contiguos en cada fila y en cada columna.
Por ejemplo:

M =
1 2
3 4

[diffX, diffY] = gradient(M)

diffX =
1 1
1 1

diffY =
2 2
2 2

Se aprecia que diffX es la diferencia entre los elementos de las filas y diffY es la diferencia entre los elementos de las columnas.

Aplicando este concepto a las imagenes en escala de grises :

function fotocopia(imagen, salida)
im = imread(imagen);
[diffX,diffY] = gradient(im);
fotocopia = (diffX.^2 + diffY.^2).^(1/2);
fotocopia = fotocopia * 3;
fotocopia = 255 - fotocopia;
imwrite(fotocopia,salida);
endfunction

El operador . es para que se haga la operación a cada elemento de la matriz (elevar al cuadrado elemento por elemento)
La multiplicación por 3 es para realzar los bordes
La resta es para que el fondo quede blanco y el contorno oscuro (255 = blanco, 0 = negro).

fotocopia("plum.jpg","fotocopia.jpg");






Tuesday, February 16, 2010

Recuerdo




El año 2005 programé un juego de naves en C con la librería ncurses, usando caracteres ASCII.
Aprendí muchas cosas y sentí gran satisfacción al ver mi jueguito terminado. No creo que el código sea un ejemplo, pero fue para mí una pequeña victoria.
Os dejo el link para descargar el código y el ejecutable.
PD: Las balas no se veen porque estan mal programadas, su velocidad depende del procesador.

Monday, January 11, 2010

Puntero void*

Un puntero void* es un puntero genérico que se puede usar para hacer funciones que pueden recibir y/o devolver distintos tipos de datos según sea el caso. O sea que usando este tipo de puntero puedes hacer por ejemplo una función que trabaje con enteros si se le pasan punteros a enteros o con una estructura si se le pasan punteros a la estructura.
En el siguiente ejemplo se hace un casting a otro tipo de puntero para que así el compilador sepa cuantos bytes debe sumar a la dirección base, en este caso el casting es a char* por lo tanto el compilador sumará tamElem*k*sizeof(char) bytes a la dirección base.
Esta función recibe de argumento la función de comparación y busca en un arreglo el argumento llamado valor, en caso de hallarlo retorna el indice del elemento en el arreglo, si no encuentra al elemento en el arreglo retorna -1.



int busquedaLineal(void *valor, void *dirBase, int tamElem, int cantElem, int (*comparacion) (void*,void*)) {
int k;
for(k=0; k < cantElem; k++) {
void *elemActual = (char*)dirBase + tamElem*k;
if( comparacion(valor,elemActual) == 0 ) {
return k;
}
}
return -1;
}

Tuesday, December 15, 2009

Editando sonido con Octave

Octave es un software muy parecido a Matlab, pero libre. Trae consigo un sin fin de funciones matemáticas, sobre todo para trabajar con matrices.
Una de las muchas cosas interesantes que se pueden hacer con este software es cargar un archivo de audio en una matriz y editarlo.

Un archivo de audio tiene tres propiedades :

Muestras por segundo (Hz)
Número de bits por muestra
Cantidad de canales.

Usando la función wavread se puede leer un archivo WAV. Un sonido monofónico se guardará en una matriz de una columna, un sonido stereo una matriz de dos columnas, etc.

Sonido original:



Efecto de eco :


#archivo entrada, archivo salida, sample rate(ej. 44100,22050,etc)
function ecoAudio(nombre_wav, salida_wav, samplerate_hz)
wav_matrix = wavread(nombre_wav); #leer wav
desp = int32( size(wav_matrix)(1)/20 );
m2 = shift(wav_matrix,desp);
wav_matrix = wav_matrix + m2;
wavwrite(wav_matrix,samplerate_hz,salida_wav);
endfunction


Aplicando efecto de eco:




Cambio de rapidez :


#archivo entrada, archivo salida,sample rate,rapidez
function rapidezAudio(nombre_wav, salida_wav, samplerate_hz, rapidez)
wav_matrix = wavread(nombre_wav);
wavwrite(wav_matrix, samplerate_hz*rapidez, salida_wav);
endfunction


Reproduciendo a la mitad de su velocidad:



Reproduciendo al doble de su velocidad:


Reproducir al revés :



#archivo entrada, archivo salida, sample rate
function revertirAudio(nombre_wav, salida_wav,samplerate_hz)
wav_matrix = wavread(nombre_wav);
wav_matrix = flipud(wav_matrix); #revertir filas
wavwrite(wav_matrix,samplerate_hz,salida_wav);
endfunction


Reproduciendo al revés:

Wednesday, December 2, 2009

Usando un entero como un arreglo de caracteres

Si tenemos una variable de tipo int por lo general ocupará 4 bytes de memoria, los que podremos usar literalmente a nuestro antojo. Por ejemplo podemos usar este espacio como un arreglo de 4 elementos de 1 byte cada uno.

Ejemplo uso de un entero como un arreglo de caracteres:



#include <stdio.h>

int main() {

int num;
num=0;
( (char *)&num )[0] = 7;
( (char *)&num )[1] = 3;
printf("%i %i\n",( (char*)&num )[0],( (char*)&num )[1]);
*( (char *)&num ) = 2;
*( (char *)&num + 1) = 4;
printf("%i %i\n",( (char*)&num )[0],( (char*)&num )[1]);
printf("%d\n",num);
}


Lo anterior imprime :

7 3
2 4
1026

La variable num queda como 1026 porque:
| 0000 0000 |0000 0000 | 0000 0100 | 0000 0010 |
| 0 | 0 | 4 | 2 |

La idea de este ejemplo es comprender mejor cómo funciona el lenguaje porque en la práctica usar un entero como un arreglo de char no hace que el código sea más simple.