modification for face recognition utility
[face-privacy-filter.git] / web_demo / face-privacy.js
1 /*
2   ===============LICENSE_START=======================================================
3   Acumos Apache-2.0
4   ===================================================================================
5   Copyright (C) 2017-2018 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
6   ===================================================================================
7   This Acumos software file is distributed by AT&T and Tech Mahindra
8   under the Apache License, Version 2.0 (the "License");
9   you may not use this file except in compliance with the License.
10   You may obtain a copy of the License at
11
12   http://www.apache.org/licenses/LICENSE-2.0
13
14   This file is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18   ===============LICENSE_END=========================================================
19 */
20 /**
21  face-privacy.js - send frames to an face privacy service; clone from image-classes.js
22
23  Videos or camera are displayed locally and frames are periodically sent to GPU image-net classifier service (developed by Zhu Liu) via http post.
24  For webRTC, See: https://gist.github.com/greenido/6238800
25
26  D. Gibbon 6/3/15
27  D. Gibbon 4/19/17 updated to new getUserMedia api, https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
28  D. Gibbon 8/1/17 adapted for system
29  E. Zavesky 10/19/17 adapted for video+image
30  E. Zavesky 05/05/18 adapted for row-based image and other results
31  E. Zavesky 05/30/18 forked model generic code to `demo-framework.js`, switch to flat image
32  */
33
34 "use strict";
35
36 /**
37  * main entry point
38  */
39
40 // called one time when document is ready
41 $(document).ready(function() {
42     var urlDefault = getUrlParameter('url-image');
43     if (!urlDefault)
44         urlDefault = "http://localhost:8884/classify";
45     demo_init({
46         classificationServer: urlDefault,
47         protoList: [["model.pixelate.proto", true], ["model.detect.proto", false], ["model.recognize.proto", false] ]
48     });
49 });
50
51
52
53 // what do we do with a good processing result?
54 //
55 //  data: the raw body from the response
56 //  dstImg: the dom element of a destination image
57 //  methodKeys: which protomethod was selected
58 //  dstImg: the dom element of a destination image (if available)
59 //  imgPlaceholder: the exported canvas image from last source
60 //
61 function processResult(data, dstDiv, methodKeys, dstImg, imgPlaceholder) {
62     var hd = $(document.body).data('hdparams');
63     if (methodKeys) {
64         //console.log(request);
65         var bodyEncodedInString = new Uint8Array(data);
66         //console.log(bodyEncodedInString);
67         //console.log(bodyEncodedInString.length);
68         $("#protoOutput").prop("disabled",false);
69         hd.protoPayloadOutput = bodyEncodedInString;
70
71         // ---- method for processing from a type ----
72         var msgOutput = hd.protoObj[methodKeys[0]]['root'].lookupType(hd.protoObj[methodKeys[0]]['methods'][methodKeys[1]]['typeOut']);
73         var objOutput = null;
74         try {
75             objOutput = msgOutput.decode(hd.protoPayloadOutput);
76         }
77         catch(err) {
78             var errStr = "Error: Failed to parse protobuf response, was the right method chosen? (err: "+err.message+")";
79             console.log(errStr);
80             dstDiv.html(errStr);
81             return false;
82         }
83         var nameRepeated = null;
84
85         // NOTE: this code expects one top-level item to be an array of nested results
86         //  e.g.   Image{mime_type, image_binary}
87         //  e.g.   DetectionFrameSet [ DetectionFrame{x, y, ...., mime_type, image_binary}, .... ]
88
89         //try to crawl the fields in the protobuf....
90         var numFields = 0;
91         $.each(msgOutput.fields, function(name, val) {           //collect field names
92             if (val.repeated) {     //indicates it's a repeated field (likely an array)
93                 nameRepeated = name;      //save this as last repeated field (ideally there is just one)
94             }
95             numFields += 1;
96         });
97
98         var typeNested = methodKeys[0]+"."+msgOutput.name;
99         if (nameRepeated) {
100             objOutput = objOutput[nameRepeated];  // dereference neseted object
101             typeNested = methodKeys[0]+"."+msgOutput.fields[nameRepeated].type;
102         }
103         else {
104             objOutput = [objOutput];    // simple singleton wrapper for uniform code below
105         }
106
107         //grab the nested array type and print out the fields of interest
108         var msgOutputNested = hd.protoObj[methodKeys[0]]['root'].lookupType(typeNested);
109         //console.log(msgOutputNested);
110         var domTable = $("<tr />");
111         var arrNames = [];
112         $.each(msgOutputNested.fields, function(name, val) {           //collect field names
113             var nameClean = val.name;
114             if (nameClean != 'imageBinary') {
115                 domTable.append($("<th />").html(nameClean));
116                 arrNames.push([nameClean, val.repeated]);
117             }
118         });
119         domTable = $("<table />").append(domTable);     // create embedded table
120
121         // loop through all members of array to do two things:
122         //  (1) find the biggest/best image
123         //  (2) print out the textual fields
124         var objBest = null;
125         $.each(objOutput, function(idx, val) {
126             if ('imageBinary' in val) {
127                 // at this time, we only support ONE output image, so we will loop through
128                 //  to grab the largest image (old code could grab the one with region == -1)
129                 if (objBest==null || val.imageBinary.length>objBest.imageBinary.length) {
130                     objBest = val;
131                 }
132             }
133
134             var domRow = $("<tr />");
135             $.each(arrNames, function(idx, field_data) {      //collect data from each column
136                 //add safety to avoid printing repeated rows!
137                 domRow.append($("<td />").html(!field_data[1] ?
138                     val[field_data[0]] : val[field_data[0]].length + " items"));
139             });
140             domTable.append(domRow);
141         });
142         dstDiv.empty().append($("<strong />").html("Results")).show();
143         dstDiv.append(domTable);
144
145         //did we find an image? show it now!
146         if (objBest != null) {
147             //some images are too big for direct btoa/array processing...
148             //dstImg.attr('src', "data:"+objBest.mimeType+";base64,"+strImage).removeClass('workingImage');
149             dstImg.attr('src', BlobToDataURI(objBest.imageBinary, objBest.mimeType)).removeClass('workingImage');
150         }
151         else if (imgPlaceholder) {
152             dstImg.attr('src', imgPlaceholder).removeClass('workingImage');
153         }
154         else {
155             var errStr = "Error: No valid image data was found and no placeholder, aborting display.";
156             console.log(errStr);
157             dstDiv.html(errStr);
158             return false;
159         }
160     }
161     else {       //legacy code where response was in base64 encoded image...
162         var responseJson = $.parseJSON(data);
163         var respImage = responseJson[0];
164         // https://stackoverflow.com/questions/21227078/convert-base64-to-image-in-javascript-jquery
165         dstImg.attr('src', "data:"+respImage['mime_type']+";base64,"+respImage['image_binary']).removeClass('workingImage');
166     }
167 }