Enviado el 13 diciembre, 2010 por nauj27
En el nuevo proyecto que estoy escribiendo para Android, me he visto en la necesidad de analizar cada una de las imágenes que recoge la cámara durante la vista previa de la misma. Según la documentación el formato que deben de implementar los dispositivos con Android es YCbCr_420_SP codificado como NV21. Aunque en principio se podrían especificar otros formatos es extraño que algún terminal tenga otro formato implementado así que deberemos de usar ese si queremos que funcione en el mayor número de plataformas y dispositivos posibles.
Desarrollo de Cylon Detector para Android
En cada frame recibido se desea analizar si existe la cara de una persona, por lo que hay que convertir la imagen a Bitmap y pasarla al detector de caras que provee el API. Pues bien, existe un problema y es que la factoría para crear Bitmaps no acepta ese formato. Hay varias soluciones por la red, pero unas son para Android 2.2 en adelante, otras son implementaciones en C para hacerlas usando el NDK como librería independiente, y otras símplemente son demasiado complejas para lo que aquí se necesita.
Al final lo que he hecho es analizar el formato de los datos en base a su definición y crear el Bitmap a partir de estos datos para la imagenen blanco y negro. Podría hacerse para la imagen en color símplemente leyendo todos los datos y haciendo uso de las funciones de conversión de YCrCb a RGB pero ello requeriría mayor tiempo de proceso incluyendo varias multiplicaciones en coma flotante. Aquí solo necesitamos en principio detectar si hay una cara en la imagen o no, y para ello es suficiente con que la imagen sea en blanco y negro. Para obtener la imagen en blanco y negro lo que he hecho ha sido leer los valores de luminancia (luminosidad), que según el formato NV21 están en la primera parte del array y convertir cada valor a un punto RGB con el mismo valor. El resultado, aunque no se aprecia demasiado bien en la imagen anterior, no es completamente una imagen en blanco y negro, sino que aparecen zonas saturadas de un color amarillo. La conversión que estoy realizando no es del todo correcta pero es cuestión de convertir y acotar correctamente los valores.
Por si a alguien le es de utilidad, esto es un recorte de la parte más importante que he programado para la conversión de NV21 a Bitmap:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| /**
* @author nauj27
* The Utils class contains utilities for CylonDetector.
*/
public class Utils {
/**
* See http://www.fourcc.org/yuv.php#NV21 for more information.
* We only read luminance for speed up the whole process.
* All colors of the image are set to the luminance value and
* this way we obtains a black and white image for processing.
*
* @param data The data array in NV21 (YCbCr_420_SP) format.
* @return Black and white bitmap decoded from NV21 input data.
*/
public static Bitmap getBitmapFromNV21(byte[] data, int width, int height) {
int pixelsNumber = width * height;
int[] colors = new int[pixelsNumber];
for (int pixel = 0; pixel < pixelsNumber; pixel++) {
colors[pixel] = Color.rgb(data[pixel], data[pixel], data[pixel]);
}
return Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
}
} |
/**
* @author nauj27
* The Utils class contains utilities for CylonDetector.
*/
public class Utils {
/**
* See http://www.fourcc.org/yuv.php#NV21 for more information.
* We only read luminance for speed up the whole process.
* All colors of the image are set to the luminance value and
* this way we obtains a black and white image for processing.
*
* @param data The data array in NV21 (YCbCr_420_SP) format.
* @return Black and white bitmap decoded from NV21 input data.
*/
public static Bitmap getBitmapFromNV21(byte[] data, int width, int height) {
int pixelsNumber = width * height;
int[] colors = new int[pixelsNumber];
for (int pixel = 0; pixel < pixelsNumber; pixel++) {
colors[pixel] = Color.rgb(data[pixel], data[pixel], data[pixel]);
}
return Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
}
}
Editada: El modo correcto de convertir el valor de luminancia a escala de grises para crear la imagen lo he sacado finalmente del proyecto zxing, y es el que dejo a continuación:
1
2
| grey = data[pixel] & 0xff;
colors[pixel] = 0xff000000 | (grey * 0x00010101); |
grey = data[pixel] & 0xff;
colors[pixel] = 0xff000000 | (grey * 0x00010101);
Esto es lo que iría dentro del bucle for para que sea interpretado correctamente por el Bitmap.createBitmap como mapa de color ARGB_8888.
Etiquetas: android, camera, color, development, java, nv21, ycbcr, yuv :: Archivado en Android, Programación
Enviado el 10 diciembre, 2010 por nauj27
Me he decidido a echarle un vistazo al HTML5 y a la representación de una superficie Canvas para dibujar en 2D. Este tipo de superficie permitirá en un futuro que ya está aquí hacer juegos para la web en HTML real que se puedan usar en cualquier dispositivo sin necesidad de complementos de terceros, léase Adobe Flash.
La verdadera utilidad y potencia es poder dibujar en tiempo real sobre la superficie y a provechar todas las características de dibujo que nos proporciona, cosas que no he usado en mi ejercicio particular. Sin embargo me ha servido como introducción al uso de canvas en HTML y aquí queda como ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| <html>
<head>
<title>HTML 5 Canvas example</title>
<script type="text/javascript">
var x = 50;
var y = 50;
var dx = 1;
var dy = 1;
var myCanvas;
var myContext;
var pelota;
var fondo;
var main = function() {
// Se inicializa el canvas
myCanvas = document.getElementById("mycanvas");
myContext = myCanvas.getContext("2d");
// Se cogen los elementos de imagen para pintar
pelota = document.getElementById("pelota");
fondo = document.getElementById("fondo");
// Se pinta el fondo y la pelota en el canvas
myContext.drawImage(fondo, 0, 0, fondo.width, fondo.height);
myContext.drawImage(pelota, x, y);
window.setInterval("moverPelota()", 10);
};
var moverPelota = function() {
if ((x > myCanvas.width - pelota.width) || (x < 0)) {
dx = -dx;
}
if ((y > myCanvas.height - pelota.height) || (y < 0)) {
dy = -dy;
}
x += dx;
y += dy;
myContext.drawImage(fondo, 0, 0, fondo.width, fondo.height);
myContext.drawImage(pelota, x, y);
};
</script>
<style type="text/css">
canvas { border: 2px solid black; }
canvas#mycanvas { width: 320px; height: 170px; }
img { display: none; }
</style>
</head>
<body onload="main();">
<canvas id="mycanvas">
Aquí debería de aparecer un balón rebotando.
</canvas>
<img id="pelota" src="pelota.png" width="49px" height="49px" />
<img id="fondo" src="fondo.jpg" width="320px" height="170px" />
</body>
</html> |
<html>
<head>
<title>HTML 5 Canvas example</title>
<script type="text/javascript">
var x = 50;
var y = 50;
var dx = 1;
var dy = 1;
var myCanvas;
var myContext;
var pelota;
var fondo;
var main = function() {
// Se inicializa el canvas
myCanvas = document.getElementById("mycanvas");
myContext = myCanvas.getContext("2d");
// Se cogen los elementos de imagen para pintar
pelota = document.getElementById("pelota");
fondo = document.getElementById("fondo");
// Se pinta el fondo y la pelota en el canvas
myContext.drawImage(fondo, 0, 0, fondo.width, fondo.height);
myContext.drawImage(pelota, x, y);
window.setInterval("moverPelota()", 10);
};
var moverPelota = function() {
if ((x > myCanvas.width - pelota.width) || (x < 0)) {
dx = -dx;
}
if ((y > myCanvas.height - pelota.height) || (y < 0)) {
dy = -dy;
}
x += dx;
y += dy;
myContext.drawImage(fondo, 0, 0, fondo.width, fondo.height);
myContext.drawImage(pelota, x, y);
};
</script>
<style type="text/css">
canvas { border: 2px solid black; }
canvas#mycanvas { width: 320px; height: 170px; }
img { display: none; }
</style>
</head>
<body onload="main();">
<canvas id="mycanvas">
Aquí debería de aparecer un balón rebotando.
</canvas>
<img id="pelota" src="pelota.png" width="49px" height="49px" />
<img id="fondo" src="fondo.jpg" width="320px" height="170px" />
</body>
</html>
El resultado puede verse en la web del ejemplo de uso de canvas.
Las imágenes se precargan ocultas (con display: none) porque según la especificación del HTML5 si la imagen no ha sido completamente cargada no se pintará nada. Cargándolas de este modo nos aseguramos de que se han leído completamente antes de su uso en el canvas.
Las pruebas las he realizado sobre Mozilla Firefox 4.0 Beta 7. En cualquier navegador que implemente canvas sobre html5 debería de representarse correctamente. Entre estos navegadores se incluyen Safari, Opera o Chrome. Si eres usuario de Internet Explorer ¿a qué esperas para cambiar a un navegador real?
Etiquetas: canvas, HTML, html5, JavaScript :: Archivado en HTML, JavaScript
Enviado el 7 noviembre, 2010 por nauj27
Quizá hayáis visto el anuncio de Samsung donde se anuncia una televisión 3D que según ellos muestra la imagen a 600Hz. Tendemos a comparar las cosas nuevas que vemos y oímos con aquellas que conocemos, por lo que mi reacción al ver el anuncio fue pensar:
Menuda tontería ponerle 600Hz, si por encima de los 85Hz nadie es capaz de apreciar la diferencia, ¿qué sentido tiene?
Pues bien, buscando un poco en Google he encontrado lo siguiente en una web oficial de Panasonic de Canadá:
A standard video signal is actually a series of still images, flashed on screen so quickly that we believe we are watching a moving image. The typical frame rate used in North America is 60 frames per second (60Hz) meaning that a TV would display 60 individual still images every second. Sub-field drive is the method used to flash the individual image elements (dots) on a plasma panel. For each frame displayed on the TV the Sub-field drive flashes the dots 10 times or more, meaning that the dots are flashing 600 times per second (600Hz) or more. (Example: 60 frames per second x 10 sub-fields = 600 flashes per second).
Lo que significa en una traducción más o menos libre:
Una señal estándar de video es una serie de imágenes fijas, que pasan por la pantalla tan rápido que hacen creer que se está viendo una imagen en movimiento. La tasa de refresco usual usada en Norte América es de 60 imágenes por segundo (60 Hz) lo cual significa que una TV mostrará 60 imágenes únicas por segundo. Sub-field motion es el método usado en los paneles de plasma para encender cada punto individual de la imagen (píxeles). Para cada imagen mostrada en la pantalla, el método sub-field motion enciende los puntitos 10 veces o más, al mostrar 60 imágenes por segundo esto hace que la imagen se pinte 600 veces por segundo, que son los 600Hz del anuncio.
La imagen aparece más nítida al ojo por la tecnología usada para mantener cada fotograma en pantalla, pero en realidad la frecuencia de cambio de imagen es la misma que en otras televisiones.
Sitio en inglés donde encontré que explicaban lo mismo.
Etiquetas: 600hz, 60hz, anuncio, samsung, subfield, tv, Video :: Archivado en Multimedia, Video
Enviado el 29 octubre, 2010 por nauj27
Siempre que pierdo la configuración me tiro unos días buscando la forma de volver a hacer funcionar los mensajes MMS con Android. Todas las configuraciones que por ahí aparecen hablan de crear dos perfiles, uno para Internet y otro para los MMS. Finalmente habría que ir a la configuración de los mensajes y asignar el perfil de MMS.
El problema es que en Android no funciona así. Desde la configuración de los mensajes no se puede elegir un perfil y si se crean dos perfiles distintos hay que elegir uno y el otro no se usa para nada.
La solución es crear un único perfil con una mezcla de las dos configuraciones. Lo voy a poner aquí, porque siempre que pierdo la configuración por el cambio de ROM me cuesta volver a hacerlo funcionar.
En el menú Ajustes > Conexiones inalámbricas > Redes móviles > APN > MENÚ > APN nuevo:
Nombre: Simyo
APN: gprs-service.com
Proxy:
Puerto:
Nombre de usuario:
Contraseña:
Servidor:
MMSC: http://217.18.32.180:8080
Proxy MMS: 217.18.32.181
Puerto de MMS: 8080
Protocolo MMS: WAP 2.0
MMC: 214
MNC: 19
Tipo de autenticación: Ninguno
Tipo de APN: default,mms
Y funcionará así tanto la conexión de red GPRS/3G/HDSPA/HDSPA+ como los mensajes MMS.
Etiquetas: android, internet, mms, simyo :: Archivado en Android
Enviado el 2 octubre, 2010 por nauj27
Desde que empecé el desarrollo de ColorPicker para Android tenía en mente liberar el código, pero hasta ahora ponía las típicas excusas: que si el código está muy feo, que si tengo que ponerme. Hoy ya se puede decir que he cumplido con lo que anuncié. Acabo de liberar el código con la versión GPL v3 en la web oficial de ColorPicker.
Para mantener el control de los cambios he venido usando Mercurial. El mejor modo de descargarse el código fuente de ColorPicker es usando por tanto un cliente de Mercurial, disponible para todas las plataformas más usadas.
Tengo varias ideas en mente para esta aplicación, unas que se me ocurrieron y otras muchas que me han ido sugiriendo tanto en persona como en los comentarios del propio Android Market. En las próximas semanas podrán verse novedades y actualizaciones de la aplicación.
Etiquetas: android, colorpicker, java, Programación :: Archivado en Android, Programación
Enviado el 23 junio, 2010 por manol32
Hoy nos acompaña un nuevo «artilugio», es un «cuentakilómetrosgpsaltímetro…» y por supuesto se ha convertido en la estrella de la excursión. Comprobamos que va bien de velocidad, va bien de distancia, va bien de…todo, este aparato funciona a la primera y sin libro de instrucciones.
Llegamos a Dílar, disfrute de su agua, de sus vistas, de sus caminos, pasamos por debajo del nogal y ya estamos en el río. ¡Podrían haber dejado algo sin asfalto para los nostálgicos de la arenilla suelta y el rachazo fácil!, así que toca poner la suspensión bien blanda y en menos de nada estamos arriba del todo, hoy no podemos beber agua de nuestra fuente favorita, pero ver el rio a tope de agua conforta y relaja, como siempre mogollón de gente andando, con el perro suelto y ciclistas (ojo, que vimos a una chica y esto merece un punto de atención). En este momento nos damos cuenta que hay caminos, excursiones y rutas que son buenas aunque sea la enésima vez que las hagas, y subir al río es de lo mejor que podemos realizar en menos de 2 horas.
A la vuelta, empiezan los percances:
- Un mosquito del tamaño de un 747 decide aterrizar en el ojo derecho de uno de nosotros.
- Se avería el cuentakilómetros (no el maxifunción que va de cine) que por supuesto es arreglado en un periquete.
- Cuando llegamos a Dílar de vuelta noto que la rueda de atrás va desinflándose poco a poco, pero cuando es inevitable que debe ser hinchada paramos en la gasolinera y la pongo a tope, como siempre, los pinchazos son por rachas y nos iremos preparando para lo que venga, otra cosa que no me gusta es ver el maldito pincho en la rueda, NUNCA SE DEBE QUITAR aunque esté ahí diciéndome ¡Sácame! porque una vez que lo quites la rueda ya no se desinflará poco a poco, sino rápidamente.
Hasta otra…
Etiquetas: dílar, excursión, mountain, MTB :: Archivado en MTB
Enviado el 21 junio, 2010 por nauj27
Vestigios: Exposición por Diana Aranda
Alquife y sus gentes protagonizan “Vestigios”, una exposición que nos habla de recuerdos, abandono y éxodo. De cómo un lugar muerto es capaz de devolvernos la vida de sus habitantes a través de los objetos deteriorados que dejaron en el camino.
La muestra está compuesta por 15 fotografías tomadas en este municipio granadino situado en la parte meridional de la comarca de Guadix. El pueblo contaba con un yacimiento minero de hierro en torno al cual se desplazaron los trabajadores junto con sus familias formando una pequeña comunidad provista de todos los detalles: colegio, hospital, iglesia, teatro…
Al cerrarse la mina las gentes que vivían allí abandonaron el lugar dejando atrás muchas de sus pertenen- cias y recuerdos. Años después, “Vestigios” nos invita a recorrer las calles de Alquife y a recrear el pasado a través de esos objetos.
“Vestigios” es el primer gran proyecto de la joven artista granadina Diana Aranda en el que se combinan el diseño y la fotografía, dando como resultado esta exposición y un catálogo donde se recogen todas las imágenes. Las fotografías van acompañadas de un breve texto a modo de guía para el que se contó con la colaboración de Pablo Ramirez y Ariadna Gau.
Del 21 de Junio al 30 de Septiembre
De lunes a viernes de 8:30 a 22:30 y sábados de 9:00 a 14:30 horas.
Entrada Gratuita
Lugar: Escuela Arte Granada, c/ Dr. Olóriz 6
Etiquetas: exposición, fotografía :: Archivado en Eventos
Enviado el 19 junio, 2010 por nauj27
Como de costumbre hemos elegido un sábado de temporada para hacer una de las vueltas más largas en kilómetros de las que componen nuestros recorridos habituales. La diferencia esta vez ha sido que íbamos un grupo algo más grande de lo habitual, cuatro personas en lugar de dos, y que a la vuelta hemos tomado algunos atajos que evitan algo de asfalto.
Debido a los problemas en tiempos de carga de la web con rutas anteriores he decidido hacer una cuenta en wikiloc.com de modo que ahora podréis disfrutar mejor de las rutas sin problemas de lentitud.
Haciendo clic en el globo verde que indica el comienzo de la ruta se pueden ver todos los datos y el perfil de la misma.
Distancia recorrida: 42,79 Km.
Es una ruta muy sencilla pero que sirve para ir poniéndose en forma para cuando vengan las rutas bonitas de montaña.
Etiquetas: ciclismo, MTB :: Archivado en MTB