Capítulo 5: Alternativas de implementación del algoritmo HOG
5.7 Comprobación de funcionamiento del bloque IP desarrollado
5.7.2 Diseño software en Vivado SDK
Una vez se ha generado el archivo bitstream que recoge la programación del hardware, es necesario llevar a cabo la programación del código que será ejecutado por el procesador ARM que integra el dispositivo Zynq.
Para implementar la comunicación Ethernet se va a hacer uso de la biblioteca LwIP o
Lightweight IP. LwIP es una implementación en código libre de la pila de protocolos TCP/IP pensada principalmente para sistemas empotrados debido a su bajo uso de recursos y su sencilla configuración.
5.7.2.1
Inicializaciones
El empleo de la pila de protocolos LwIP se lleva a cabo utilizando una API denominada Raw API que reúne todo lo necesario para el empleo de esta pila sin necesidad de un sistema operativo. La puesta en funcionamiento de esta pila de protocolos requiere de una serie de inicializaciones que configuran todos los parámetros de esta, como la dirección IP utilizada, el puerto de escucha y escritura o el empleo de DHCP.
El bloque HLS también lleva asociado un conjunto de drivers que reúnen todas las funciones que permiten controlar el funcionamiento del bloque. En el caso de esta aplicación, estas funciones se encuentran declaradas en el archivo xhog.h que debe ser incluido en el código para poder utilizarlas posteriormente.
Antes de poder utilizar el bloque IP, este debe ser inicializado. Esta inicialización se lleva a cabo con la siguiente instrucción:
XHog_Initialize(&HOG0,XPAR_HOG_0_DEVICE_ID);
El primer argumento de la llamada a esta función es una estructura de datos que se usará posteriormente para el control de este bloque y donde se recoge la dirección de memoria donde se encuentran mapeados los registros del bus AXI-Lite. El segundo argumento es el nombre dado al bloque IP en el archivo xparameters.h donde se recoge todo el mapeado en memoria del sistema y que se emplea para conocer dicha dirección.
5.7.2.2
Lectura de imagen, procesamiento y escritura de
descriptores HOG
Una vez el sistema esta inicializado correctamente, este espera recibir una imagen por el puerto Ethernet. Para ello, se comprueba constantemente si se están recibiendo datos y, cuando se reciben, estos son almacenados en memoria.
Una vez que se ha recibido la imagen completa, es el momento de iniciar su procesamiento. El primer paso es configurar los buses AXI4 del bloque IP con las direcciones de memoria desde la cual se debe leer la imagen y en la que se escribirán los descriptores calculados. Para ello, se hace uso de dos de las funciones incluidas en los drivers generados por HLS:
XHog_Set_imagen(&HOG0,(u32)0x18000000);//Configuración de la dirección base de memoria DDR donde se almacena la imagen a leer
XHog_Set_descriptor_hog(&HOG0,(u32)dir_hog);//Configuración de la dirección de memoria donde se escribirán los descriptores calculados por el algoritmo HOG
La función XHog_Set_imagen se emplea para configurar la dirección de memoria desde donde el bus AXI4 leerá la imagen. Esta función está asociada a la configuración del bus AXI4 con un offset de tipo slave en el código HLS, tal y como se explicó en el apartado 5.6.1.2.1, que permite configurar esta dirección desde software empleando el bus AXI-Lite. En este caso, se indica la dirección 0x18000000 de memoria ya que esa dirección es donde la imagen es almacenada tras ser recibida vía Ethernet.
De la misma forma, la función XHog_Set_descriptor_hog permite configurar la dirección a partir de la cual se escribirán los descriptores calculados.
Como se detallará en el siguiente capítulo, la búsqueda de personas en una imagen supone recorrerla desplazando las ventanas de detección y decidiendo para cada una de ellas si se localiza una persona o no. Con el objetivo de realizar un procesamiento similar, cada imagen de 1024x1280 píxeles debe ser procesada múltiples veces, desplazando la ventana de detección de 128x64 píxeles por ella. El desplazamiento de la ventana debe realizarse superponiendo las ventanas entre sí, con el objetivo de cubrir todas las áreas donde podría encontrarse una persona.
En este caso se ha estipulado un stride de ventana de 8 píxeles en dirección horizontal y 16 píxeles en dirección vertical. Así, el número de ventanas en cada dirección se obtendrá teniendo en cuenta el número de píxeles de la imagen, el tamaño de la ventana y el solapamiento de estas con las siguientes operaciones:
numWindowsX = ((1280 - 2 - 64) / stridex) + 1;//Número de ventanas en dirección horizontal
numWindowsY = ((1024 - 2 - 128) / stridey) + 1;//Número de ventanas en dirección vertical
Una vez determinado el número de ventanas, es necesario ejecutar el bloque hardware una vez para cada una de ellas. Como se ha explicado anteriormente, el bloque debe recibir también el offset dentro de la imagen que indica la esquina superior izquierda de la ventana de detección a procesar. Para ello, se han utilizado dos bucles anidados, uno recorriendo la dirección vertical y otro la horizontal. Utilizando estos bucles, el tamaño de la imagen y el
stride de ventana aplicado, es posible determinar el píxel donde comienza la ventana a procesar. Cabe destacar que la multiplicación por un factor 2 es debido al formato YUV 4:2:2 en el que se encuentra la imagen almacenada en memoria.
inicio = y*2*stridey*1280+x*2*stridex; //Cálculo del offset de la ventana a procesar dentro de la imagen completa.
XHog_Set_inicio_ventana(&HOG0, inicio); //Configuración del offset en el bloque HLS
Una vez se han configurado todos los parámetros que necesitaba el bloque HLS, es necesario indicarle que puede empezar su ejecución. Para ello se emplea la función XHog_Start, que se incluye en los drivers del bloque, tal y como puede observarse en la línea siguiente:
XHog_Start(&HOG0); //Inicio procesamiento HOG
Una vez el procesamiento ha comenzado, se espera a que este termine su ejecución antes de iniciar el procesamiento de una nueva ventana. Para conocer cuando la ejecución ha terminado, se emplea la función XHog_IsDone que devuelve un nivel alto cuando esto sucede.
while(!XHog_IsDone(&HOG0)) //Se comprueba si el procesamiento ha terminado
{ }
Cuando el procesamiento de la función ha terminado, el descriptor calculado para la ventana procesada se encuentra almacenado en la dirección de memoria fijada por dir_hog. Con el objetivo de que la siguiente iteración no sobrescriba los resultados de la anterior, es necesario modificar la dirección base de escritura, incrementando esta en 1152 valores.
dir_hog = dir_hog + 1152;
XHog_Set_descriptor_hog_V(&HOG0,(u32)dir_hog);
Una vez se han procesado todas las ventanas de una imagen, se envían todos los descriptores almacenados en DDR a un ordenador empleando el puerto Ethernet, de forma similar al procedimiento de lectura de la imagen.