El set de servicios de cognitive services de Microsoft, proyecto conocido como «Project Oxford» hasta el pasado build (evento en donde se realizo su lanzamiento oficial), es una colección de APIS gratuitas que nos permite construir aplicaciones inteligentes,con solo unas cuantas lineas de código, sobre cualquier plataforma(python, Android,iOs,C#, java etc), para cualquier tipo de dispositivo. Tal como lo menciono Harry Shum, Vicepresidente ejecutivo de Microsoft Research «Give your apps a human side»; Estas APIS estan agrupadas en 5 areas principales: Computer Vision, Speech Recognition,Natural language, Knowledge y Search, durante su intervención en el build, Harry menciono algunas showcase apps, que vale la pena mencionarlas:
How-Old.net: Es una aplicación que a partir de una fotografia,usando el API de face recognition, incluida dentro de la suite de servicios de cognitive services, es capaz de predecir la edad de la persona.
TwinsOrNot.net: Esta aplicación, al igual que el anterior, se apoya en el API de face recognition y la de Bing, para determinar el porcentaje de parecido entre dos personas. si llega al 100% eso quiere decir que has encontrado a tu gemelo!.
Es realmente fascinante lo que podemos llegar a hacer, si integramos en nuestros desarrollos este tipo de servicios, A continuación le dejo un ejemplo de ello, presentado por el Microsoft CEO Satya Nadella, durante el keynote :
En este primer post introductivo, les enseñaré como consumir el api de reconocimiento de emociones usando Node.js.
El API de reconocimiento de emociones, recibe como entrada una imagen e identifica dentro de la misma las caras de las personas y sus emociones, actualmente este servicio que se encuentra en beta, es capaza de detectar emociones de alegría, tristeza, sorpresa, ira, miedo, desprecio, disgusto o neutral; Al momento de usar el API, debemos de considerar lo siguiente: Los formatos de imagen soportados son: JPEG, PNG, GIF, BMP, el tamaño de la imagen no debe exceder los 4mb, el tamaño de las caras debe estar entre 36×36 hasta 4096×4096 pixeles para poder ser detectadas. Para cada imagen, el número máximo de caras detectadas es 64. Si no se detecta ninguna cara, el servicio devolverá una matriz vacía. El desprecio y disgusto son emociones experimentales.
Para Empezar debemos ingresar al sitio de Microsoft Cognitive services, registrarnos y posteriormente iniciar sesión:
- El siguiente paso, consiste en obtener nuestra API Key:
A continuación, abrimos visual studio y procedemos entonces a crear nuestro proyecto, desde el menu File/New/New Project:
Luego, agregamos nuestro archivo de configuración:
A nuestro archivo de configuración adicionamos dos variables EMOTION_API_KEY, EMOTION_API_ENDPOINT:
config.json:
{ | |
"EMOTION_API_KEY": "<API>", | |
"EMOTION_API_ENDPOINT": "https://api.projectoxford.ai/emotion/v1.0/recognize" | |
} |
Así debe de quedar nuestro archivo server.js
server.js (server)
//1. cargamos nuestras dependencias | |
var Hapi = require("hapi"); | |
var Path = require('path'); | |
var Util = require("util"); | |
var Fs = require('fs'); | |
var Http = require('http'); | |
var Request = require('request'); | |
//2. Leemos nuestro archivo de configuración | |
var config = {}; | |
Fs.readFile('./config.json', 'utf8', function (err, data) { | |
config = JSON.parse(data.toString('utf8').replace(/^\uFEFF/, '')); console.log(config); | |
}); | |
//3. Instanciamos nuestro objeto server, el cual se encargará de atender y administrar todas las conexiones entrantes. | |
var server = new Hapi.Server(); | |
//4. Inicializamos los modulos(plugins hapi) | |
server.register(require('inert'), function (err) { | |
if (err) { | |
console.error('Failed to load plugin:', err); | |
} | |
}); | |
//5. especificamos el puerto por el cual, nuestro objeto server atenderá conexiones | |
server.connection({ port : 3000 }); | |
//6. Definimos las rutas de nuestra app | |
server.route({ | |
path: "/" , method: "GET", handler: { | |
file: Path.join(__dirname, 'src/views') + "/index.html" | |
} | |
}); | |
//7.Contenido estatico de nuestro app (.css, .js, images etc) | |
server.route({ | |
path: "/public/{path*}", method: "GET", handler: { | |
directory: { path: Path.join(__dirname, 'public'), listing: true } | |
} | |
}); | |
/* | |
* 8. esta función se encarga de recibir la imagen enviada por el usuario desde la pagina index.html(front-end), | |
* e invokar el api de reconocimiento de expresiones de cognitive services | |
*/ | |
server.route({ | |
path: '/upload', | |
method: 'POST', | |
config: { | |
payload: { | |
//restricciones de archivo | |
output: 'stream', | |
maxBytes: 1048576 * 10, /*10MB*/ | |
parse: true, | |
allow: 'multipart/form-data' | |
} | |
}, handler: function (request, reply) { | |
var data = request.payload; | |
if (data.file) { | |
var fileName = Path.basename(data.file.hapi.filename);//obtenemos el nombre de la imagen | |
var src = Path.join(__dirname, Util.format('public/upload/%s', fileName)); //definimos la ruta en donde quedará guardada la imagen en nuestro server | |
//copiamos la imagen en nuestro servidor | |
var stream = Fs.createWriteStream(src); | |
data.file.pipe(stream);// | |
//si esta operación se realiza con exito | |
data.file.on('end', function (err) { | |
if (err) reply(err); | |
//invocamos el Api de reconocimiento de expresiones de Microsoft cognitive services | |
var req = Request( | |
{ | |
url: config.EMOTION_API_ENDPOINT,//url de la api | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/octet-stream',//formato de envío de la imagen al api | |
'Ocp-Apim-Subscription-Key': config.EMOTION_API_KEY,//suscription API KEY | |
} | |
}, function (error, response, body) { | |
if (error) { | |
reply(error); //en caso de que se algo salga mal, retornamos al cliente dicho error | |
} else { | |
// si todo sale bien, devolvemos al cliente la respuesta del API | |
reply({ 'uri' : Util.format('/public/upload/%s', fileName), 'info': body }).code(200); | |
} | |
}); | |
Fs.createReadStream(src).pipe(req);//enviamos la imagen como un stream al api | |
}); | |
} | |
} | |
}); | |
//ejecutamos nuestro server | |
server.start(function (err) { | |
if (err) { throw err; } console.log('Server running at:', server.info.uri); | |
}); |
Creamos dos archivos mas en nuestro proyecto index.html(en la raíz) y app.js (public/js):
index.html
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta charset="utf-8" /> | |
<title>Emotion API Node js</title> | |
</head> | |
<body> | |
<form id="frmUploadImage"> | |
<input type="file" name="file" id="inputImage"> | |
<button type="submit" class="btn btn-default">Cargar foto</button> | |
</form> | |
<canvas id="canvasLoadImage"></canvas> | |
<script src="/public/vendor/jquery/dist/jquery.js"></script> | |
<script src="/public/js/app.js"></script> | |
</body> | |
</html> |
app.js (client)
$(document).ready(function () { | |
$form = $("#frmUploadImage"), $inputFile = $('#inputImage'); | |
$form.on("submit", function (e) { | |
e.preventDefault(); | |
if ($inputFile.get(0).files.length === 0) { | |
alert("No ha seleccionado ninguna imagen"); | |
return false; | |
} | |
var formData = new FormData($(this)[0]); | |
//enviamos la imagen cargada por el usuario al servidor | |
$.ajax({ | |
url: '/upload', | |
type: 'POST', | |
data: formData, | |
async: false, | |
cache: false, | |
contentType: false, | |
processData: false, | |
success: function (data) { | |
console.log(data); | |
previewImage(data);//visualizamos la imagen si todo sale bien | |
} | |
}); | |
}); | |
function drawPoint(x, y, ctx) { | |
ctx.beginPath(); ctx.arc(x, y, 2, 0, 2 * Math.PI, true); ctx.fill(); | |
} | |
function previewImage(data) { | |
var c = document.getElementById("canvasLoadImage"); | |
var ctx = c.getContext("2d"); | |
var img = new Image(); | |
img.onload = function () { | |
//obtenemos las dimensiones de la imagen | |
c.width = this.width; | |
c.height = this.height; | |
//dibujamos la imagen en nuestro canvas | |
ctx.drawImage(this, 0, 0); | |
//lista de caras detectadas dentro de la imagen | |
var faces = JSON.parse(data.info); | |
$.each(faces, function (index, face) { | |
//obtenemos la posisción de cada cara dentro de nuestra imagen | |
var rec = face.faceRectangle; | |
ctx.fillStyle = '#DF0174'; | |
ctx.globalAlpha = 0.1; | |
ctx.fillRect(rec.left, rec.top, rec.width, rec.height); | |
ctx.globalAlpha = 1; | |
drawPoint(rec.left, rec.top, ctx); | |
drawPoint(rec.left + rec.width, rec.top, ctx); | |
drawPoint(rec.left, rec.top + rec.height, ctx); | |
drawPoint(rec.left + rec.width, rec.top + rec.height, ctx); | |
ctx.strokeStyle = 'red'; | |
ctx.restore(); | |
ctx.fillStyle = '#DF0174'; | |
ctx.font = "20px Arial"; | |
ctx.stroke(); | |
var max, maxScore; | |
$.each(face.scores, function (key, value) { | |
if (!max || parseFloat(value) > parseFloat(max)) { | |
max = parseFloat(value); maxScore = key; | |
} | |
}); | |
ctx.fillText(maxScore, rec.left + (rec.width / 2), rec.top + (rec.height / 2)); | |
}); | |
}; | |
img.src = data.uri;//url de la imagen en el servidor | |
} | |
}); |
Y finalmente la demo funcionando!.
El codigo fuente lo pueden descargar de: Emotion-API-Microsoft-Cognitive-Services-Nodejs
Espero les sea de utilidad, hasta la proxima ocasión
Gracias!
Hola, me gusto mucho tu articulo, quisiera usar la api pero comparando dos rostros, tal y como lo hace twinsornot.org que me recomiendas???
Hola @porrasmurojesus, también exitse un método para ello: https://westus.api.cognitive.microsoft.com/face/v1.0/findsimilars, voy a sacar algo de tiempo para hacer un tutorial sobre lo que me dices