traspas - Universidad de Alicante

Anuncio
Desarrollo avanzado en Android
Miguel Ángel Lozano, Boyán Bonev, Pablo Suau, Juan Manuel Sáez
{malozano,boyan,pablo,jmsaez}@dccia.ua.es
Mobile Vision Research Lab
Dep. Ciencia de la Computación e Inteligencia Artificial
Instituto Universitario de Investigación en Informática
Universidad de Alicante
Esquema


Mobile Vision Research Lab

Orígenes: robótica móvil y visión

Trabajo actual
Desarrollo avanzado en Android

NDK

NEON

Necessitas Mobile Vision Research Lab

Creación en 2011

Origen: Robot Vision Group

Miembros

Francisco Escolano

Miguel Ángel Lozano

Juan Manuel Sáez

Pablo Suau

Antonio Peñalver

Boyán Bonev
Actividades de investigación

Visión artificial (monocular y estéreo)

Robótica móvil


Reconocimiento de patrones (teoría de la información)
Visión en dispositivos móviles
Visión móvil en robótica
Visión móvil en robótica
Visión móvil en robótica
Reconocimiento de patrones
Reconocimiento de patrones
Visión móvil en el teléfono
Visión en Android

Métodos estándar de manejo de imágenes 
Clase Bitmap

setPixels, getPixels

Array de enteros

Formato ARGB_8888

Operaciones a nivel de bit

Alternativa: getPixel, setPixel

Necesidad de copiar imágenes
Visión en Android

SetPixels y getPixels muy lentos


Ejemplo: pasar a gris, Samsung Galaxy S, imagen de 320x240, 10 segundos (con enteros)
Alternativas

NDK

NEON

Necessitas
Android NDK

http://developer.android.com/sdk/ndk/index.html

Herramienta instalada por separado


Código nativo en C para las partes críticas de la aplicación
Requiere

Android 1.5 o superior

Android 2.2 o superior para tratar con imágenes
Java Native Interface



Plataforma para ejecutar código escrito en otros lenguajes desde Java
http://java.sun.com/developer/onlineTraining/Pr
ogramming/JDCBook/jni.html http://java.sun.com/developer/onlineTraining/Pr
ogramming/JDCBook/jniexamp.html Ejemplo NDK


Carpeta jni

Android.mk

archivo.c
Contenido de Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE
:= imagenes
LOCAL_SRC_FILES := nativo.c
LOCAL_LDLIBS
:= -llog -ljnigraphics -lm
include $(BUILD_SHARED_LIBRARY)
Ejemplo NDK

Contenido de nativo.c (1)
#include
#include
#include
#include
#include
#include
#include
<jni.h>
<string.h>
<math.h>
<time.h>
<stdlib.h>
<android/bitmap.h>
<android/log.h>
// La macro LOGE permite mostrar en el log de android (ejecutando en un terminal adb -logcat)
// diferentes mensajes de error. El formato de los parámetros es exactamente igual a los del
// printf de c
#define
LOG_TAG "libimages"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
// FROM RGB888 TO RGB565
// r,g and b values are 8-bit values (from 0 to 255)
inline int rgb(int r, int g, int b) {
return((r>>3<<11) + (g>>2<<5) + (b>>3));
}
// FROM RGB565 TO RGB888
inline int red(uint16_t color) { return (color&0xf800)>>11<<3;}
inline int green(uint16_t color) { return (color&0x07e0)>>5<<2;}
inline int blue(uint16_t color) { return (color&0x001f)<<3;}
Ejemplo NDK

Contenido de nativo.c (2)
// Convertir a escala de grises
void colorToGray(AndroidBitmapInfo info, uint16_t *pixels16) {
int i,r,g,b,gray;
}
for (i=0;i<info.width*info.height;i++) {
r = red(pixels16[i]);
g = green(pixels16[i]);
b = blue(pixels16[i]);
gray = (299*r + 587*g + 114*b)/1000; // Las operaciones se hacen con
//enteros para que el procesamiento sea más rápido
pixels16[i] = rgb(gray, gray, gray);
}
Ejemplo NDK

Contenido de nativo.c (3)
// Método que se llamará desde java. El formato del nombre debe ser como se muestra. En primer lugar la palabra
// Java, seguida por el nombre del paquete, el nombre de la clase, y el nombre del método (en este caso processImage)
JNIEXPORT jfloat JNICALL Java_rvg_ua_es_Gris_procesarImage(JNIEnv * env, jobject bitmap)
{
AndroidBitmapInfo info;
void *pixels;
int ret;
jfloat timep;
clock_t start, finish;
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
LOGE("Fallo en AndroidBitmap_getInfo()! error=%d", ret);
return;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {
LOGE("El formato del bitmap no es RGB_565 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
LOGE("Fallo en AndroidBitmap_lockPixels()! error=%d", ret);
return;
}
// EMPEZANDO PROCESAMIENTO
uint16_t *pixels16 = (uint16_t *)pixels;
start = clock();
// Transformar a escala de grises
colorToGray(info, pixels16);
// TERMINANDO PROCESAMIENTO
AndroidBitmap_unlockPixels(env, bitmap);
finish = clock();
timep = ((double)finish - (double)start)/CLOCKS_PER_SEC;
return timep; // El método devuelve el tiempo de ejecución
}
Ejemplo NDK


Compilación

Directorio jni

ndk­build

Se genera el fichero libimagenes.so
Importante: si no se cambió el código Java, hacer un Clear del proyecto
Ejemplo NDK

Utilizar código nativo desde Java
private
native float processImage(Bitmap bitmap);
static {
System.loadLibrary("images");
}

Tiempo: 0.2s
NEON


Set de instrucciones ARMv7
Arquitectura SIMD (Single Instruction Multiple Data)




Registros vectoriales a los que se les aplica una misma operación
32 registros de 64 bits (ó 16 registros de 128 bits)
Procesamiento imágenes, video, gráficos
http://www.arm.com/products/technologies/neo
n.php Usando NEON en Android

Conjuntamente con NDK

Añadir a Android.mk
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS := -DHAVE_NEON=1
LOCAL_SRC_FILES += native-neon.c.neon
endif
LOCAL_C_INCLUDES := $(NDK_ROOT)/sources/cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
include $(NDK_ROOT)/sources/cpufeatures/Android.mk

Extensión ­neon.c a archivos con código NEON
Usando NEON en Android

Librería cpu­features.h para la comprobación de la existencia de instrucciones NEON
// Comprobando la existencia del set de instrucciones NEON
if (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM &&
(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)!=0 &&
(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_ARMv7)!=0) {
LOGE(”NEON disponible”);
} else {
LOGE("El procesador no es ARMv7 o no es compatible con NEON");
return(-1);
}

Código alternativo en caso de incompatibilidad con NEON
Set de instrucciones NEON


http://gcc.gnu.org/onlinedocs/gcc/ARM­NEON­
Intrinsics
Ejemplos

Suma:


Comparación:

uint32x2_t vadd_u32 (uint32x2_t, uint32x2_t) uint32x2_t vceq_u32 (uint32x2_t, uint32x2_t) Ejemplo NEON (1)
// Transforms image from rgb to grayscale
void rgbtogray(AndroidBitmapInfo info, uint8_t *pixels) {
int i;
// Tamaño total de la imagen en pixels
int n = info.width*info.height;
// Puntero auxiliar para acceder en cada iteracion del bucle
// a una posicion absoluta de la imagen, en lugar de ir incrementando
// el puntero pixels
uint8_t *auxp = pixels;
int pos = 0;
// Tres variables vectoriales compuestas por 8 valores de 8 bits. En
// concreto, estos son los coeficientes por los que se van a multiplicar
// los valores RGB de cada pixel para obtener el tono de gris
uint8x8_t rfac = vdup_n_u8(77);
uint8x8_t gfac = vdup_n_u8(151);
uint8x8_t bfac = vdup_n_u8(28);
// Dividimos el tamaño entre 8 porque los pixeles se van a procesar de
// 8 en 8 (por lo que hay 8 veces menos iteraciones)
n /= 8; // 8 pixels are processed simultaneously
for (i=0;i<n;i++) {
uint16x8_t temp;
uint8x8_t result;
// La variable rgb se comportará como un registro, con un unico
// campo, un vector llamado val, de 4 componentes. Cada componente
// de ese vector es un registro vectorial
// Asi que aqui lo que estamos haciendo es almacenar las cuatro
// componentes RGBA de los ocho pixeles actuales (apuntados por
// auxp) en cuatro registros vectoriales
uint8x8x4_t rgb = vld4_u8(auxp);
// Lo siguiente son instrucciones de multiplicacion y
// multiplicacion con acumulacion
temp = vmull_u8(rgb.val[0], rfac);
temp = vmlal_u8(temp, rgb.val[1], gfac);
temp = vmlal_u8(temp, rgb.val[2],
bfac);
Ejemplo NEON (2)
// Se realiza un desplazamiento para dividir y volver a tener
// valores entre 0 y 255
result = vshrn_n_u16(temp,8);
// Se asigna
// del pixel
rgb.val[0] =
rgb.val[1] =
rgb.val[2] =
el mismo valor de intensidad a todas las componentes
para tener una imagen en tonos de gris
result;
result;
result;
// Se vuelven a almacenar los 4 conjuntos de 8 bytes
// (correspondientes a los 8 pixeles procesados esta iteracion)
// en su posicion correspondiente de memoria
vst4_u8(auxp,rgb);
// Se apuna al siguiente conjunto de pixeles (aumentamos 8*4 bytes)
pos += 32;
// En lugar de ir incrementando el valor de pixels, vamos calculando
// auxp como una suma absoluta.
// Si no se hacía de esta forma el resultado no era correcto. Quiza
// es debido a que el procesamiento con NEON se realiza de forma
// asincrona
auxp = pixels + pos;
}
return;
}

Tiempo: 0.04s (50 veces más rápido que sin NEON, 250 veces más rápido que sin NDK)
Necessitas

Port de QT a Android



http://sourceforge.net/p/necessitas/home/necessitas/
Ventajas

Código nativo

Compilación basada en el set de NEON
Inconvenientes

Estado muy prematuro

No se manejan correctamente algunos eventos de interfaz

Necesidad de instalar gran cantidad de librerías (Ministro)
Necessitas

Reconstrucción 2D en tiempo real basada únicamente en visión
Necessitas
Necessitas
Desarrollo avanzado en Android
Miguel Ángel Lozano, Boyán Bonev, Pablo Suau, Juan Manuel Sáez
{malozano,boyan,pablo,jmsaez}@dccia.ua.es
Mobile Vision Research Lab
Dep. Ciencia de la Computación e Inteligencia Artificial
Instituto Universitario de Investigación en Informática
Universidad de Alicante
Descargar