Face Recognition REST API

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!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.