bluebrowncustomgreenorangepinkredturquoiseyellow
  • Layout Style
  • Texture for Boxed, Framed, Rounded Layout Background

  • Font
    • Body:

    • Menu:

    • Title:

    * Fonts are used to example. You able to use 600+ google web fonts in the backend.

Mail info@moldeointeractive.com.ar
Blog - Moldeo Coop.

Demo de MIRU (AR) versión Web - Angular y Facetracker

Estamos contentos de anunciar que nuestra versión de Facetracker en la web ya está funcionando con un rendimiento digno.

Como muchos saben, a principio de año desarrollamos una integración de OpenFace a nuestro software Moldeo, para poder realizar trackeo de rostros en 3D dentro de instalaciones interactivas. Los resultados fueron más que favorables, llegando a realizar una instalación en la Alianza Francesa de Buenos Aires, dentro de Noviembre Digital. Sin embargo, hemos logrado un objetivo todavía más superador, y es lograr implementar dicho sistema en la web, gracias a la tecnología de Angular. De este modo, ya tenemos funcionando la Demo de MIRU(AR) Web, del cual puede verse un video demo en el siguiente link:

 

https://www.youtube.com/watch?v=l9c0IRLo-94

 

Seguiremos informando muy pronto!

Angular y JSFeat (OpenCV.js) - Computer Vision en JavaScript

Es muy posible que, realizada una breve investigación por la web (especialmente sitios como GitHub), los programadores se encuentren con intentos de migración del famoso paquete de librerías OpenCV, especializada en procesamiento de imagen en tiempo real, a JavaScript. Muchos de los trabajos realizados son dignos de destacar, como el caso de js-objectdetect con su excelente rendimiento, o tracking.js con sus resultados finales. Sin embargo, es posible que al día de la fecha ninguno se asemeje a las posibilidades ofrecidas por JSFeat, una librería para JavaScript que ofrece Features similares a las de OpenCV. Y ahi radican sus resultados: no intenta ser una migración de OpenCV a JavaScript, sino que utiliza el lenguaje de JavaScript para conseguir resultados acordes al entorno de trabajo (browser). Y cómo no, si está en JavaScript en Moldeo Interactive queremos que funcione en Angular.

Pero para la correcta integración de JSFeat con Angular es necesario comprender el funcionamiento interno de esta librería, especialmente porque los ejemplos disponibles están un poco entorpecidos por otras dependencias que no vienen al caso (jQuery, gui, profiler, etc). JSFeat aplica sus funciones matemáticas sobre un Canvas, esto quiere decir que nuestra captura de video de la WebCam debe estar en un Canvas. Y para dicha tarea, vamos a tener que conseguir la imagen de nuestra WebCam desde la tag Video con Angular y, empleando el propio Angular, enviarla a un Canvas. Existen diversas formas de realizar esta tarea, pero en principio necesitamos incluir en el HTML del componente una tag video oculta y una tag canvas, que identificaremos para poder acceder a ambas:

<video width="640" height="480" #hardwareVideo [hidden]="true"></video>
<canvas id="canvas" width="640" height="480"></canvas>

En este caso, ya se definieron los valores de ancho y alto, no obstante es posible (y recomendable) hacerlo desde la clase de TypeScript correspondiente, la cual de todas formas necesitamos modificar. En primer lugar, vamos a dejar preparado el entorno, importando el OnInit y el ViewChild de Angular:

import { Component, OnInit, ViewChild } from '@angular/core';

Acto seguido, y teniendo acceso a todo lo necesario, vamos a declarar nuestras variables a utilizar en nuestra clase:

@ViewChild('hardwareVideo') hardwareVideo: any;
constraints: any;
canvas: any;
context: any;

La variable hardwareVideo recupera el elemento HTML con ese mismo nombre (que si revisamos previamente, es el nombre que le pusimos a nuestra tag video). Por otra parte, la variable constraints se utiliza para darle directivas al stream de video; canvas será donde llamaremos nuestro elemento canvas; y context la encargada de almacenar el contexto de canvas. Nada nuevo bajo el sol, comencemos a ensamblar. Dejaremos el constructor vacío ya que nada estará inicializado desde ahí. Entonces, armaremos el ngOnInit de la siguiente forma:

ngOnInit(){
 this.constraints = {
     audio: false,
     video: {
      width: {ideal:640},
      height: {ideal:280}
    }
  };

  this.videoStart();
}

¿Qué pasa acá en el ngOnInit? Le ponemos contenido a nuestra variable constraints (que en este caso no aporta casi nada, pero podemos definirle los FPS o el aspecto del video si nos interesa) e inicializamos la función videoStart que contiene lo siguiente:

videoStart(){
    let video = this.hardwareVideo.nativeElement;
    let n = <any>navigator;

    n.getUserMedia = ( n.getUserMedia || n.webkitGetUserMedia || n.mozGetUserMedia  || n.msGetUserMedia );

    n.mediaDevices.getUserMedia(this.constraints).then(function(stream) {
      if ("srcObject" in video) {
        video.srcObject = stream;
      } else {
        video.src = window.URL.createObjectURL(stream);
      }
      video.onloadedmetadata = function(e) {
        video.play();
      };
    });

    this.canvas = document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');

    this.loop();
}

Acá hay parte de la magia. Ya que esta función se llama en el ngOnInit y solo se ejecutará una vez, directamente se utiliza para el conocido objecto mediaDevices de navigator, y de este la función getUserMedia, que nos permite acceder a los dispositivos multimedia conectados a la computadora. Lo lógico sería hacer unas condicionales de compatibilidad con el navegador un poco más exhaustivas, pero para una primera prueba es suficiente. Finalmente, se le asigna el elemento canvas a la variable canvas, y luego el contexto (en este caso es 2D) a la variable context. Pero vemos al final un elemento desconocido, estamos llamando una función llamada loop, ¿dónde está y que contiene?

loop = () =>{
    this.context.drawImage(this.hardwareVideo.nativeElement, 0, 0, this.canvas.width, this.canvas.height);

    requestAnimationFrame(this.loop);
}

Recordemos algo rápidamente, la función videoStart solo se ejecuta una vez, lo cual es útil para inicializar ciertas funciones. Pero tenemos un problema, necesitamos pasar constantemente la imagen de la tag video al contexto de canvas. Para esto, llegó a nuestro rescate la función requestAnimationFrame(). Sin entrar en mucho detalle, la estructura de esta función loop permite ejecutar constantemente su contenido, algo que nos viene perfecto. Si compilamos el código, deberíamos poder ver la imagen de nuestra WebCam, solo que no se trata de una imagen de la tag video, sino que del canvas. Ahora sí, hora de integrar JSFeat, para esto vamos a instalarlo mediante npm:

npm install jsfeat --save

Simplemente nos limitaremos a importarlo a la clase de TypeScript que necesitemos (en este caso, la misma donde aplicamos el video al canvas):

import * as jsfeat from 'jsfeat';

Solo con esto ya podremos empezar a aplicar las funciones de JSFeat, siempre llamando al objecto jsfeat antes que nada. ¿Cómo se aplica? Lo ideal es utilizar la propia función loop, y del mismo modo que con JavaScript se debe utilizar un getImageData() del contexto del canvas. La función loop quedaría entonces de este modo:

loop = () =>{
    this.context.drawImage(this.hardwareVideo.nativeElement, 0, 0, this.canvas.width, this.canvas.height);
    var imageData = this.context.getImageData(0, 0, 640, 480);

    jsfeat.imgproc.grayscale(imageData.data, 640, 480, this.img_u8);

    var data_u32 = new Uint32Array(imageData.data.buffer);
    var alpha = (0xff << 24);
    var i = this.img_u8.cols*this.img_u8.rows, pix = 0;
    while(--i >= 0) {
        pix = this.img_u8.data[i];
        data_u32[i] = alpha | (pix << 16) | (pix << 8) | pix;
    }
    this.context.putImageData(imageData, 0, 0);

    requestAnimationFrame(this.loop);
}

Aquí simplemente se aplica una función para pasar la imagen a escala de grises; lo que le sigue previo al requestAnimationFrame() es la manera de aplicar la transformación denuevo al contexto del canvas (sino por más que realice el proceso no podremos verlo). Nota: la variable this.img_u8 está creada también de formaglobal, e inicializada en el ngOnInit de este modo this.img_u8 = new jsfeat.matrix_t(640, 480, jsfeat.U8C1_t), forma parte de una clase propia de jsfeat (matrices) que se necesita para aplicar gran parte de sus funciones.

De esta manera tendremos funcionando JSFeat en un entorno Angular, permitiendo optimizar el rendimiento (más aún si cabe) en lo que producción de código se refiere. Actualmente estamos utilizando esta implementación como Resource en nuestra producción de MoldeoJS. ¿Siguiente paso? Quizás potenciar los resultados mediante el uso de GPU. Los mantendremos informados.

Repositorio del código ngJSFeat, con filtro grayscale y blur: https://github.com/ibuioli/ngJSFeat

Utilizar BLE en apps de Cordova - Android e iOS

En los diversos proyectos donde nos hemos visto involucrados, suele necesitarse una forma personalizada de capturar datos (mediante sensores), procesarlos y enviarlos a un dispositivo para su posterior uso. Lo natural es pensar en implementar Bluetooth, por su eficacia al transmitir a dispositivos cercanos y la posibilidad de implementarlo con micro-controladores Arduino. Por otro lado, es muy probable que necesitemos desarrollar una app para dispositivos móviles, que posteriormente almacene la información o la envíe a un servidor. Y así como venimos utilizando, nos interesa que dicha app se pueda desarrollar con Apache Córdova por sus posibilidades tanto en producción como en testeo al valerse de JavaScript.

Es común encontrar diversos módulos Bluetooth para Arduino, desde los primeros HM01 hasta los más modernos. El problema aparece con las compatibilidades y iOS. Los módulos HM01 son de funcionamiento sencillo, mientras que los más modernos como los HM10 y HM11 (por ejemplo, el modelo CC2541) utilizan la tecnología Bluetooth Low Energy (BLE).  Estos módulos tienen una serie de ventajas frente al resto en el mercado:

 

- Son económicos y se consiguen de diversas formas mediante importadores locales (a diferencia de los iBeacons).

- Se pueden utilizar en cualquier Arduino o incluso familias de micro-controladores que implementen comunicación Serial.

- Consumen poca energía para transmitir o recibir datos, utilizando 3.3v de Arduino y no 5v como la mayoría de los módulos.

- No necesitan ser emparejados con un dispositivo.

- No necesitan tener un disociador de voltaje en el puerto TX.

- Son compatibles con Android (a partir de la 4.3) y con iOS (es el único hardware de bluetooth compatible con iOS de todas formas).

 

Es por esto que, muy probablemente, estemos interesados en utilizarlos. Existen muchas maneras de conectar el módulo HM10/11 y no nos vamos a centrar en eso ahora. Tiene seis terminales pero solo necesitamos conectar 4: GND, VCC (3.3v, con 5v se quemará), TX y RX. En internet pueden encontrarse circuitos de complejidad baja, e incluso el código que no es más que un código donde el dato que queremos enviar por Bluetooth se debe escribir en el Serial (el Serial es conveniente generarlo nosotros, usando la librería de Arduino SoftwareSerial, asignando entonces un TX y RX personalizados).

Para el caso de una app Cordova será necesario desarrollar de forma distinta a un módulo Bluetooth convencional, y en eso si vamos a centrarnos. Para empezar, vamos a necesitar un plugin específico llamado BLE Central, el cual no tiene un ejemplo funcional para los módulos HM10/11. Aún así, podemos utilizar el ejemplo desarrollado para el módulo Adafruit Bluefruit LE, ya que su funcionamiento interno es compatible con los HM10/11 (en caso de poseer un módulo Adafruit Bluefruit LE, utilizando ese ejemplo sin modificaciones será suficiente).

El cambio dentro del código es muy sencillo y está relacionado con la UUID del módulo Bluetooth BLE HM10/11. En el ejemplo del Adafruit Bluefruit LE buscamos el archivo www/js/index.js, y ahí mismo buscamos la siguiente declaración de JavaScript:

 

// this is Nordic's UART service
var bluefruit = {
    serviceUUID: '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
    txCharacteristic: '6e400002-b5a3-f393-e0a9-e50e24dcca9e', // transmit is from the phone's perspective
    rxCharacteristic: '6e400003-b5a3-f393-e0a9-e50e24dcca9e'  // receive is from the phone's perspective
};

 

Podemos ver que este fragmento simplemente declara la UUID y los puertos TX y RX que la app necesita para escuchar/enviar. Lo vamos a modificar de la siguiente manera:

 

var bluefruit = {
    serviceUUID: 'ffe0',
    txCharacteristic: 'ffe1', // transmit is from the phone's perspective
    rxCharacteristic: 'ffe1'  // receive is from the phone's perspective
};

 

Esta declaración hará que la app esté buscando todos los dispositivos con BLE y no un dispositivo en particular. Al compilar la app y ejecutarla desde un teléfono móvil (con el Bluetooth activado) podremos ver que la app va a encontrar un dispositivo llamado, generalmente, BT05 y que será nuestro Arduino conectado a un módulo BLE. También es posible encontrar dispositivos llamados unknow, que suelen tratarse de dispositivos que se encuentran cerca pero a los cuales no tenemos acceso.

Migrando la impresora fiscal a v9

Bueno... es eso. Es todo un trabajo, para nada trivial. Por lo pronto hay que agregar el router /web/database/get_list e implementarlo en Odoo. Así que va a llevar su esfuerzo, no es un cambio de API como uno se imaginaba al principio. Luego de eso, seguiremos trabajando para que desde la extensión se pueda acceder Odoo. Y una vez que pasó eso, debe poderse desde la extensión de Chrome ejecutarse un test-corto, y luego un test largo. El paso siguiente es poder realizar lo mismo con el módulo odoo_fpoc.

Así que lo vamos a mantener al tanto del trabajo

Activar scroll en app de Cordova para iOS

"¡Ayuda! Mi app de ios no hace scroll con Cordova".

Parece una banalidad, e incluso una simpleza, pero es muy probable que al intentar desarrollar una App con Cordova que buscamos compilar par iOS tengamos el problema de no poder scrollear. Esto ocurre generalmente cuando utilizamos una tag iframe. El problema es una simpleza y la solución igual:

<div style="width:100%;height:100%;overflow:scroll !important;-webkit-overflow-scrolling:touch !important">
    <iframe src="http://www.tupulperia.com" scrolling="yes" style="width:100%;height:100%" frameborder="0"></iframe>
</div>

Como se puede apreciar en este pequeño fragmento de html, el truco viene de la mano de CSS. Al estar el webview de iOS basado en su navegador Safari, es necesario activar la regla -webkit-overflow-scrolling:touch !important, recordemos que Safari está basado en WebKit. Algo tan simple nos puede ahorrar dolores de cabeza, tales como un rechazo de Apple porque "The App don't scroll".

Publicar una App en la Apple App Store

El ambiente de las aplicaciones para móviles llegó cuando la informática ya se encontraba asentada, y cuando la web había sido un eficiente sistema para la prueba-error. Por esa razón las Apps para celulares tienen manifiestos que configuran los permisos de forma cómoda, y no un laberinto de permisos mediante el uso de HTTPS como tienen las Web Apps. Sin embargo, no todo es oro lo que reluce.

Los desarrolladores generamos aplicaciones móviles de formas diversas, pero el resultado final suele ser publicarlas en las tiendas de mayor corriente de usuarios: Google Play Store (Android) y Apple App Store (iOS). En esta oportunidad no explicaremos como subir una App a la Play Store (que de todas maneras es muy simple), sino como aventurarnos en la tarea de intentar subir una App de iOS a la App Store de Apple.

Para comenzar, vamos a asegurarnos de tener todo lo necesario antes de dedicarnos a la labor. Necesitamos, en principio, un Apple ID (que vendría a ser como una cuenta de Apple), para lo cual hay que registrarnos con nuestro email en el siguiente enlace: https://appleid.apple.com/account#!&page=create. Si somos usuarios de iPhone es muy probable que ya tengamos un Apple ID. Aún así, esto no es suficiente para que Apple te permita desarrollar Apps. Lo próximo será darnos de alta como desarrolladores (Developer) de Apple, para lo cual tendremos que pagar la suma nada despreciable de 99 dólares al año. ¿Qué pasa si al año no pagamos? Cualquier App subida será eliminada. Para esto vamos a ingresar al siguiente sitio: https://developer.apple.com/ y luego a Account. Ahí es necesario loguearnos con nuestra Apple ID y ya en la pestaña Overview nos va a pedir que realicemos un pago (Purchase). Lo haremos mediante tarjeta de crédito y esperaremos unas 48 horas a que nos llegue la confirmación del pago realizado.

Nota: Es posible que transcurridas las 48 horas y con la confirmación del pago (y el pago cobrado) sigamos sin poder acceder al menú del desarrollador y nos pida realizar otro pago. Esto se debe a que el sistema de seguridad de Apple es desastroso, y al no reconocerte como “Usuario de Mac” desconfía. Se soluciona enviando un mail al equipo técnico de Apple, quienes solucionan el inconveniente en la brevedad.

Nuestro último elemento, y no menor, es tener una Mac. No importa que queramos desarrollar únicamente, para compilar una App de iOS es necesario tener una Mac. Los trucos con máquinas virtuales han resultado en fracaso, de momento no hay forma de evitar utilizar el hardware. Además de esto vamos a tener que actualizar el OSX si no tenemos una versión reciente, ya que vamos a necesitar el Xcode en su versión 7 por lo menos. Es recomendable, además, tener un iPhone; sin embargo no es indispensable ya que los emuladores de iOS funcionan muy bien (aunque no emulan sensores ni bluetooth). Ahora sí, ya tenemos todo para empezar a subir nuestra App a la App Store.

No importa si hacemos una App con las herramientas nativas de Apple (Xcode) o mediante frameworks (Cordova), en cualquier caso vamos a tener un archivo del tipo Proyecto Xcode (Cordova no puede compilar por su cuenta, simplemente genera un archivo para el Xcode). Además, no vamos a ver el archivo compilado en ningún momento. A la hora de compilar un binario, el propio Xcode nos va a dar la opción de subirlo a la App Store, siempre y cuando toda la información necesaria sea correcta. En el Xcode vamos a buscar Preferences – Accounts y agregamos nuestra cuenta de Desarrollador de Apple haciendo click en el boton +. Acto seguido, vamos a apretar en el botón Manage Certificates, nos saldrá una ventana pop-up donde tendremos que dar de alta un certificado de distribución iOS (iOS Distribution). Apretamos en Add y seleccionamos iOS Distribution.

Nos vamos por un momento a nuestra cuenta de Desarrollador: https://developer.apple.com/account y accedemos a Overview – Certificates, Identifiers, & Profiles.

 

 

Buscamos la sección Identifiers y elegimos Apple IDs. Ahí buscamos el botón + y nos aparecerá una ventana con opciones para dar de alta un Apple ID para nuestra App. La llenamos con los datos de nuestra App, dejamos marcada la opción Explicit App ID y en Bundle ID escribimos la Bundle ID de nuestra App (si no habíamos configurado ninguna no pasa nada, vamos a crear una en ese momento). Se recomienda una Bundle ID con el formato de una URL a la inversa, por ejemplo com.tuweb.subdom. Le damos a Continue y finalizamos el registro.

Ahora vamos a necesitar crear un Provisioning Profile, para lo cual en el mismo menú vamos a buscar Provisioning Profiles – All. Apretamos el botón + y seleccionamos Distribution – App Store, le damos a Continue. Nos va a salir un menú desplegable con nuestras Apple IDs creadas, elegimos la de la aplicación deseada, continuamos y finalizamos. Si disponemos de un iPhone, este paso no suele ser necesario. Sin embargo, recomendamos generar todos los certificados que pide Apple antes de intentar publicar la aplicación.

 

 

Luego de todos estos pasos, ya estaremos en condiciones de crear el entorno de carga de nuestra App, para lo cual Apple utiliza el iTunes Connect. Ingresamos, una vez más, a nuestra cuenta de Desarrollador: https://developer.apple.com/account y buscamos la opción iTunes Connect. Nos saldrá un menú con más botones, seleccionamos My Apps.

 

 

Ya dentro, vamos a darle al botón New App y completamos los datos de nuestra aplicación. Al finalizar, le daremos al botón Create. En Pricing and Availability vamos a seleccionar el precio de nuestra App (aunque sea gratis). Vamos a notar que debajo del menú iOS App va a salir una opción con un círculo amarillo que dice 1.0. Al apretar ahí nos saldrán las opciones de la versión de la App que vamos a cargar. Necesitaremos cargar una serie de datos, como la descripción, capturas de pantalla de la App, etc. Por fin, tendremos todo listo para compilar y cargar nuestra App en la App Store.

 

 

Abrimos nuestro proyecto de Xcode (.xcodeproj) y en la pestaña General revisamos los datos de nuestra App. Prestamos especial atención en la sección Identify. Para empezar, el Bundle Identifier tiene que coincidir con el Bundle ID que dimos de alta previamente. Asimismo, el número de versión (no el número de Build) debe coincidir con el binario que vamos a subir. En este caso, al ser la primera vez que subimos una App vamos a usar el número por defecto 1.0. Si tenemos un iPhone conectado, la opción de Automatically manage signing debería firmar nuestra App de forma automática. En caso de no tener iPhone, vamos a deshabilitar la opción de Automatically manage signing y a utilizar nuestro Provisioning Profile, que generamos previamente.

Nos vamos a asegurar de que estamos compilando una versión Release y no Debug. Para esto, nos dirigimos a Product – Scheme – Edit Scheme. Seleccionamos Archive y revisamos que en Build Configuration diga Release. Volvemos a la interfaz del Xcode, y arriba a la izquierda cambiamos el compilador para que sea Generic iOS (es decir que no sea ningún Emulador ni un iPhone conectado), y nos dirigimos a Product – Archive. Si todo está correcto, nos va a salir un cartel de Build Successful y la opción de Upload to App Store. Transcurridos unos minutos, nos dirá que la App estará sincronizada con iTunes.

En este punto nuestra App pasará a estar en proceso de revisión por parte de Apple. Es necesario revisarla (en lo posible en un dispositivo) antes de mandarla y comprobar que funcione perfectamente porque, a diferencia de Google Play Store, Apple no la va a subir si no funciona perfectamente. Además de eso, es probable que Apple solicite cambios de funcionamiento e incluso estéticos, a pesar de que la aplicación no es producida por ellos, solo por utilizar su servicio. Cada proceso de revisión toma un día entero, por lo que subir una App a la App Store puede demorarse meses de desarrollo.