License text issue in image specific model repos
[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         mediaList: [
49             {
50                 'img': 'images/face_reunion.jpg',
51                 'source': 'https://flic.kr/p/bEgYbs',
52                 'name': 'reunion (flickr)'
53             },
54             {
55                 'img': 'images/face_glasses.jpg',
56                 'source': 'https://www.pexels.com/photo/close-up-photography-of-man-wearing-sunglasses-1212984/',
57                 'name': 'glasses (pexels)'
58             },
59             {
60                 'img': 'images/face_family.jpg',
61                 'source': 'https://www.pexels.com/photo/adult-affection-beautiful-beauty-265764',
62                 'name': 'family (pexels)'
63             },
64             {
65                 'img': 'images/commercial.jpg',
66                 'movie': "images/commercial.mp4",
67                 'source': 'https://www.youtube.com/watch?v=34KfCNapnUg',
68                 'name': 'commercial (pexels)'
69             },
70             {
71                 'img': 'images/face_Schwarzenegger.jpg',
72                 'source': 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/0f/A._Schwarzenegger.jpg/220px-A._Schwarzenegger.jpg',
73                 'name': 'Schwarzenegger (wikipedia)'
74             },            {
75                 'img': 'images/face_DeGeneres.jpg',
76                 'source': 'https://en.wikipedia.org/wiki/Ellen_DeGeneres#/media/File:Ellen_DeGeneres-2009.jpg',
77                 'name': 'DeGeneres (wikipedia)'
78             },
79         ]
80     });
81 });
82
83
84
85 // what do we do with a good processing result?
86 //
87 //  data: the raw body from the response
88 //  dstImg: the dom element of a destination image
89 //  methodKeys: which protomethod was selected
90 //  dstImg: the dom element of a destination image (if available)
91 //  imgPlaceholder: the exported canvas image from last source
92 //
93 function processResult(data, dstDiv, methodKeys, dstImg, imgPlaceholder) {
94     var hd = $(document.body).data('hdparams');
95     if (methodKeys) {
96         //console.log(request);
97         var bodyEncodedInString = new Uint8Array(data);
98         //console.log(bodyEncodedInString);
99         //console.log(bodyEncodedInString.length);
100         $("#protoOutput").prop("disabled",false);
101         hd.protoPayloadOutput = bodyEncodedInString;
102
103         // ---- method for processing from a type ----
104         var msgOutput = hd.protoObj[methodKeys[0]]['root'].lookupType(hd.protoObj[methodKeys[0]]['methods'][methodKeys[1]]['typeOut']);
105         var objOutput = null;
106         try {
107             objOutput = msgOutput.decode(hd.protoPayloadOutput);
108         }
109         catch(err) {
110             var errStr = "Error: Failed to parse protobuf response, was the right method chosen? (err: "+err.message+")";
111             console.log(errStr);
112             dstDiv.html(errStr);
113             return false;
114         }
115         var nameRepeated = null;
116
117         // NOTE: this code expects one top-level item to be an array of nested results
118         //  e.g.   Image{mime_type, image_binary}
119         //  e.g.   DetectionFrameSet [ DetectionFrame{x, y, ...., mime_type, image_binary}, .... ]
120
121         //try to crawl the fields in the protobuf....
122         var numFields = 0;
123         $.each(msgOutput.fields, function(name, val) {           //collect field names
124             if (val.repeated) {     //indicates it's a repeated field (likely an array)
125                 nameRepeated = name;      //save this as last repeated field (ideally there is just one)
126             }
127             numFields += 1;
128         });
129
130         var typeNested = methodKeys[0]+"."+msgOutput.name;
131         if (nameRepeated) {
132             objOutput = objOutput[nameRepeated];  // dereference neseted object
133             typeNested = methodKeys[0]+"."+msgOutput.fields[nameRepeated].type;
134         }
135         else {
136             objOutput = [objOutput];    // simple singleton wrapper for uniform code below
137         }
138
139         //grab the nested array type and print out the fields of interest
140         var msgOutputNested = hd.protoObj[methodKeys[0]]['root'].lookupType(typeNested);
141         //console.log(msgOutputNested);
142         var domTable = $("<tr />");
143         var arrNames = [];
144         $.each(msgOutputNested.fields, function(name, val) {           //collect field names
145             var nameClean = val.name;
146             if (nameClean != 'imageBinary') {
147                 domTable.append($("<th />").html(nameClean));
148                 arrNames.push([nameClean, val.repeated]);
149             }
150         });
151         domTable = $("<table />").append(domTable);     // create embedded table
152
153         // loop through all members of array to do two things:
154         //  (1) find the biggest/best image
155         //  (2) print out the textual fields
156         var objBest = null;
157         $.each(objOutput, function(idx, val) {
158             if ('imageBinary' in val) {
159                 // at this time, we only support ONE output image, so we will loop through
160                 //  to grab the largest image (old code could grab the one with region == -1)
161                 if (objBest==null || val.imageBinary.length>objBest.imageBinary.length) {
162                     objBest = val;
163                 }
164             }
165
166             var domRow = $("<tr />");
167             $.each(arrNames, function(idx, field_data) {      //collect data from each column
168                 //add safety to avoid printing repeated rows!
169                 domRow.append($("<td />").html(!field_data[1] ?
170                     val[field_data[0]] : val[field_data[0]].length + " items"));
171             });
172             if (val.x && val.y) {  //valid bounding box examples?
173                 canvas_rect(false, val.x, val.y, val.w, val.h, hd.colorSet[idx % hd.colorSet.length]);
174                 domRow.children(":nth-child(2)").append($("<div class='colorblock'/>").css(
175                     "background-color", hd.colorSet[idx % hd.colorSet.length]));
176             }
177             domTable.append(domRow);
178         });
179         dstDiv.empty().append($("<strong />").html("Results")).show();
180         dstDiv.append(domTable);
181
182         //did we find an image? show it now!
183         if (objBest != null) {
184             //some images are too big for direct btoa/array processing...
185             //dstImg.attr('src', "data:"+objBest.mimeType+";base64,"+strImage).removeClass('workingImage');
186             dstImg.attr('src', BlobToDataURI(objBest.imageBinary, objBest.mimeType)).removeClass('workingImage');
187         }
188         else if (imgPlaceholder) {
189             dstImg.attr('src', imgPlaceholder).removeClass('workingImage');
190         }
191         else {
192             var errStr = "Error: No valid image data was found and no placeholder, aborting display.";
193             console.log(errStr);
194             dstDiv.html(errStr);
195             return false;
196         }
197     }
198     else {       //legacy code where response was in base64 encoded image...
199         var responseJson = $.parseJSON(data);
200         var respImage = responseJson[0];
201         // https://stackoverflow.com/questions/21227078/convert-base64-to-image-in-javascript-jquery
202         dstImg.attr('src', "data:"+respImage['mime_type']+";base64,"+respImage['image_binary']).removeClass('workingImage');
203     }
204 }
205
206