FaceDiff facediff.com will soon launch with a full REST API for developers who need face recognition in their apps, sites, or hardware.
An preliminary example from JavaScript (JQuery plugin that calls the API) is this:
$.ceus = { faceDiffQueue: [], faceDiffResults: [], faceDiffCallback: null, sendIndex: 0, sendNext: null, errorCallback: function (err) { $.ceus.faceDiffQueue = []; console.log("ERROR:" + err.data); }, /* @function faceDiff - given a photo of a crowd returns face locations and predicted person returns: { [coords] {"face": 1, "predicted" : 95, "confidence": 15648.969559, "label":"Joe Smith"}, {"face": n, "predicted" : 104, "confidence": 8588.871966, "label":"Jane Doe"} } coords (see photoInfo) face: index of face in coords predicted: person match label: person's name for convenience * required: clientData, photoUrl */ faceDiff: function (opt, retFunc) { $.post('service', {action: 'faceDiff', photoUrl: opt.photoUrl, clientData: opt.clientData}, function (response) { var response = JSON.parse(response); if (response.success != 1) { response.data = data; errorCallback(response); return; } retFunc(response); }); }, /* @function addFbSource -- adds a new source for people to match with type of facebook friends * returns: {source} * required: fbuid */ addFbSource: function (fbuid, retFunc) { $.post('service', {action: 'addSource', type: SOURCE_TYPE_FB, data: JSON.stringify({uid:fbuid})}, function (response) { var response = JSON.parse(response); if (response.success != 1) { response.data = data; errorCallback(response); return; } retFunc(response); } ); }, /* @function toggleSourceItem - adds a new person or toggles source item if person exists * returns: {person,facecoords,status} * required: source, sourceref, photoUrl, name */ toggleSourceItem: function (opt, retFunc) { $.post('service', { action: 'toggleSourceItem', source: opt.source, sourceref: opt.sourceref, photoUrl: opt.photoUrl, name: opt.name }, function (data) { var response = JSON.parse(data); if (response.success != 1) { // error response.data = data; errorCallback(response); return; } retFunc(response); }); }, /* @function togglePersonItem - adds a new match photo to a person or toggles if exists * returns: {photo,facecoords,status,results} * required: person, sourceref, photoUrl */ togglePersonItem : function (opt, retFunc) { $.post('service', { action: 'togglePersonItem', person: '' + opt.person, sourceref: '' + opt.sourceref, photoUrl: opt.photoUrl }, function (response) { var response = JSON.parse(response); if (response.success != 1) { // error response.data = data; errorCallback(response); return; } retFunc(response); }); }, /* @function getPhotoInfo - gets coordinates of faces in a photo * returns: {clientData,photo,status,image,facecoords} * clientData: clientData you pass * photo: photo ID * status: photo status * image: image ID * facecoords: array of w,h,x,y,w2,h2,x2,y2,etc * required: person, sourceref, photoUrl * sourceref is the id of the photo, not the person */ getPhotoInfo: function (opt, retFunc) { $.post('service', { action: 'getPhotoInfo', person: '' + opt.person, sourceref: '' + opt.sourceref, photoUrl: opt.photoUrl, clientData: opt.clientData }, function (response) { var response = JSON.parse(response); if (response.success != 1) { // error $.ceus.faceDiffQueue = []; response.data = data; errorCallback(response); return; } retFunc(response); }); }, /* @function togglePhotoFace - tells facediff that a specific rectangle within a person's photo is that person's face * these photos are used as the basis for all matching functions, specifically faceDiff api calls * * returns: {clientData,photo,status,image,facecoords} * * if photo is excluded because togglePersonItem result unknown, * call will result in togglePersonItem when sourceref doesn't exist * (hence photoUrl argument) * * required: person, [photo], sourceref, photoUrl, src_[w,h,x,y] * * photoUrl is the url for the source photo of the rect */ togglePhotoFace : function (opt, retFunc) { $.post('service', { action: 'togglePhotoFace', person: '' + opt.person, photo: '' + opt.photo, sourceref: '' + opt.sourceref, photoUrl: '' + opt.photoUrl, src_w: opt.src_w, src_h: opt.src_h, src_x: opt.src_x, src_y: opt.src_y }, function (response) { var response = JSON.parse(response); if (response.success != 1) { // error response.data = data; errorCallback(response); return; } retFunc(response); }); } }; $.extend($.ceus, { queueFaceDiff: function (opt) { $.ceus.faceDiffQueue[$.ceus.faceDiffQueue.length] = opt; }, sendQueue: function (retFunc) { console.log('send queue'); $.ceus.sendIndex = 0; $.ceus.faceDiffCallback = retFunc; $.ceus.sendNext(); }, sendNext: function () { if ($.ceus.sendIndex == $.ceus.faceDiffQueue.length) { $.ceus.faceDiffQueue = []; $.ceus.faceDiffCallback($.ceus.faceDiffResults); return; } console.log('sending ' + $.ceus.sendIndex + ' of ' + $.ceus.faceDiffQueue.length) $.ceus.faceDiff($.ceus.faceDiffQueue[$.ceus.sendIndex], function (ret) { $.ceus.faceDiffResults[$.ceus.sendIndex] = ret; $.ceus.sendIndex++; setTimeout(function () { $.ceus.sendNext(); }, 1); }); } });
With this plugin I was able to quickly create an app whereby, when connected to a visitors FaceBook account:
1) For each friend with a large number of photos
2) Have user select 3 that are certainly the user (API does object detection, returns coords of faces, this was used to put a selectable box around faces)
3) From there, for those friend’s photos (and could do all other friends…) it detects relatively accurately which other photos contain that person’s face and where in the photo (x, y, width, height) that person’s face occurs
Pretty neat stuff, one of the most interesting projects I’ve worked on!