Contando pixeles.

Posted · Añadir comentario

Una de las tareas que realizaremos a menudo cuando trabajemos con video en openframeworks será recorrer la matriz de pixeles en la que se almacena cada fotograma procedente de la cámara o de la película que estemos reproduciendo. En openframeworks, dicha matriz no es bidimensional, sino que los valores RGB se almacenan, unos al lado de los otros, en una larga lista.

carta-mago-00

Es importante recordar que, por cada pixel, en la lista se almacenan tres valores; uno para la luminosidad del color rojo, otro para la luminosidad del color verde, y otro para la luminosidad del color azul. Por lo tanto, cualquier matriz de pixeles que utilicemos procedente de una imagen RGB estará compuesta por un numero valores igual al total de pixeles multiplicado por 3.

carta-mago-01

Para recorrer la matriz y realizar operaciones en cada uno de los pixeles basta con hacer una, muy sencilla, iteración con un índice que nos permita ir del primer elemento de la lista hasta el último.

unsigned char * pixels = vidGrabber.getPixels();
int totalPixels = camWidth * camHeight * 3;
for (int i = 0; i < totalPixels; i++) {
	// do something with pixels[i]  ...
}

Sin embargo, en muchas ocasiones, será necesario conocer la posición X e Y da cada pixel en la imagen, como por ejemplo, cuando queramos cambiar su tamaño, trabajar en un fragmento de la misma o hacer operaciones basadas en líneas horizontales o verticales. En ese caso la solución mas directa consiste en trabajar como si la matriz de vídeo tuviese dos dimensiones y hacer dos iteraciones, con dos índices, uno que recorra la matriz a lo alto y otro que la recorra a lo ancho. De este modo, avanzaremos a través de la imagen, de línea horizontal en línea horizontal, empezando por la parte superior izquierda y acabando en la parte inferior derecha y, en cada punto de la iteración, los índices tomarán el valor de la posición X e Y de uno de los pixeles; con ellos, podremos calcular fácilmente la posición de dicho pixel en la lista.

lectura_pixeles_00

Al igual que en el ejemplo anterior es importante recordar que por cada pixel se almacenan tres valores en la lista, por lo que el ancho de de una matriz de dos dimensiones en la que estuviese almacenada la imagen sería tres veces el ancho en pixeles de la imagen.

unsigned char * pixels = vidGrabber.getPixels();
for (int y=0; y<camHeight; y++) {
	for (int x = 0; x < (camWidth * 3); x++){
		int position = y * (camWidth * 3) + x;
		// do something with pixels[pos]  ...
	}
}

Siguiendo la misma estrategia, en uno de los foros de openframeworks, Arturo Castro propone simplificar el proceso utilizando un tercer índice para calcular de forma directa la posición en la lista.

unsigned char * pixels = vidGrabber.getPixels();
int i = 0;
for (int y=0; y<camHeight; y++) {
	for (int x = 0; x < (camWidth * 3); x++, i++){
		// do something with pixels[i]  ...
	}
}

La opción propuesta por Arturo Castro es extraordinariamente elegante, pero en los ejemplos de herm3TICa, a menudo, utilizaremos una estrategia diferente sugerida por Emanuele Mazza, que permite reducir el número de iteraciones haciendo algunas matemáticas. Consiste en utilizar un operador llamado módulo %, que devuelve el resto de una división con números enteros, para calcular la posición X e Y de cada pixel partiendo de su índice.

Si recorremos la matriz a través de un único índice, como en el primer ejemplo, y en cada iteración calculamos el resto de la división de dicho índice entre el ancho de la matriz utilizando el operador módulo, el resto equivaldrá la posición X de cada pixel. Del mismo modo si calculamos la división con números enteros del índice entre el ancho de la matriz, restando previamente ese resto al índice, el resultado equivaldrá la posición Y de cada pixel.

unsigned char * pixels = vidGrabber.getPixels();
int totalPixels = camWidth * camHeight * 3;
for (int i=0; i<totalPixels; i++) {
	int x = i % (camWidth * 3);
	int y = (i - x) / (camWidth * 3);
	// do something with pixels[i]  ...
}

La lógica de la operación es mucho mas sencilla de lo que aparenta; por cada línea que recorremos, avanzamos un total de valores igual al ancho de la supuesta matriz bidimensional.

lectura_pixeles_01

Si, por ejemplo, estamos al principio de la tercera línea, habremos avanzado dos veces el ancho de la matriz y el resultado de la división del índice entre el ancho matriz deberá ser dos. Sin embargo nos encontramos en la tercera línea, ¿por que? En realidad la tercera línea es la número dos ya que, al igual que en el Tarot, comenzamos a contar a partir del 0, es decir, contamos las líneas que hemos recorrido, no la línea en la que estamos. La primera línea, la línea 0, es la línea en la que todavía no hemos recorrido ninguna otra línea.

lectura_pixeles_02

En el ejemplo de la imagen si dividimos el índice, 14, entre 7 el resultado es 2 y el resto cero, por lo que el índice 14 se encuentra la posición 0 de la segunda línea.

lectura_pixeles_04

Por el contrario, si la división del índice entre el ancho de la matriz no es exacta, quiere decir que todavía no hemos alcanzado el final de una de las líneas. En ese caso el valor entero de la división corresponde al número de líneas que ya hemos avanzado y el resto el lugar por el que vamos en la línea que no hemos acabado.

lectura_pixeles_03

En el ejemplo de la imagen si dividimos el índice, 8, entre 7 el resultado es 1 y el resto 1, por lo que el índice 8 se encuentra en la segunda posición de la segunda línea.

lectura_pixeles_05

 
 

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies