Created
May 23, 2016 14:31
-
-
Save stephenplusplus/aa0c82b4939e5901680e41c9a89e8c03 to your computer and use it in GitHub Desktop.
Vision.prototype.detect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Vision.prototype.detect = function(images, options, callback) { | |
| var self = this; | |
| var isSingleImage = !is.array(images) || images.length === 1; | |
| if (!is.object(options)) { | |
| options = { | |
| types: options | |
| }; | |
| } | |
| var types = arrify(options.types); | |
| var typeShortNameToFullName = { | |
| face: 'FACE_DETECTION', | |
| faces: 'FACE_DETECTION', | |
| label: 'LABEL_DETECTION', | |
| labels: 'LABEL_DETECTION', | |
| landmark: 'LANDMARK_DETECTION', | |
| landmarks: 'LANDMARK_DETECTION', | |
| logo: 'LOGO_DETECTION', | |
| logos: 'LOGO_DETECTION', | |
| properties: 'IMAGE_PROPERTIES', | |
| safeSearch: 'SAFE_SEARCH_DETECTION', | |
| text: 'TEXT_DETECTION' | |
| }; | |
| var typeShortNameToRespName = { | |
| face: 'faceAnnotations', | |
| faces: 'faceAnnotations', | |
| label: 'labelAnnotations', | |
| labels: 'labelAnnotations', | |
| landmark: 'landmarkAnnotations', | |
| landmarks: 'landmarkAnnotations', | |
| logo: 'logoAnnotations', | |
| logos: 'logoAnnotations', | |
| properties: 'imagePropertiesAnnotation', | |
| safeSearch: 'safeSearchAnnotation', | |
| text: 'textAnnotations' | |
| }; | |
| var typeRespNameToShortName = { | |
| errors: 'errors', | |
| faceAnnotations: 'faces', | |
| imagePropertiesAnnotation: 'properties', | |
| labelAnnotations: 'labels', | |
| landmarkAnnotations: 'landmarks', | |
| logoAnnotations: 'logos', | |
| safeSearchAnnotation: 'safeSearch', | |
| textAnnotations: 'text' | |
| }; | |
| Vision.findImages_(images, function(err, images) { | |
| if (err) { | |
| callback(err); | |
| return; | |
| } | |
| var config = []; | |
| images.forEach(function(image) { | |
| types.forEach(function(type) { | |
| var typeName = typeShortNameToFullName[type]; | |
| if (!typeName) { | |
| throw new Error('Requested detection feature not found: ' + type); | |
| } | |
| var cfg = { | |
| image: image, | |
| features: { | |
| type: typeName | |
| } | |
| }; | |
| if (is.number(options.maxResults)) { | |
| cfg.features.maxResults = options.maxResults; | |
| } | |
| config.push(cfg); | |
| }); | |
| }); | |
| self.annotate(config, function(err, annotations, resp) { | |
| if (err) { | |
| callback(err, null, resp); | |
| return; | |
| } | |
| var originalResp = extend(true, {}, resp); | |
| var detections = images | |
| .map(groupDetectionsByImage) | |
| .map(assignTypeToEmptyAnnotations) | |
| .map(combineErrors) | |
| .map(flattenAnnotations) | |
| .map(decorateAnnotations); | |
| // If only a single image was given, expose it from the array. | |
| callback(null, isSingleImage ? detections[0] : detections, originalResp); | |
| function groupDetectionsByImage() { | |
| // detections = [ | |
| // // Image one: | |
| // [ | |
| // { | |
| // faceAnnotations: {}, | |
| // labelAnnotations: {}, | |
| // ... | |
| // } | |
| // ], | |
| // | |
| // // Image two: | |
| // [ | |
| // { | |
| // faceAnnotations: {}, | |
| // labelAnnotations: {}, | |
| // ... | |
| // } | |
| // ] | |
| // ] | |
| return annotations.splice(0, types.length); | |
| } | |
| function assignTypeToEmptyAnnotations() { | |
| // Before: | |
| // [ | |
| // {}, // What annotation type was attempted? | |
| // { labelAnnotations: {...} } | |
| // ] | |
| // | |
| // After: | |
| // [ | |
| // { faceAnnotations: {} }, | |
| // { labelAnnotations: {...} } | |
| // ] | |
| return annotations.map(function(annotation, index) { | |
| var detectionType = types[index]; | |
| var typeName = typeShortNameToRespName[detectionType]; | |
| if (is.empty(annotation)) { | |
| annotation[typeName] = []; | |
| } | |
| return annotation; | |
| }); | |
| } | |
| function combineErrors(annotations) { | |
| // Before: | |
| // [ | |
| // { error: {...} }, | |
| // { error: {...} } | |
| // ] | |
| // After: | |
| // [ | |
| // errors: [ | |
| // {...}, | |
| // {...} | |
| // ] | |
| // ] | |
| var errors = []; | |
| var spliceIndexes = []; | |
| annotations.forEach(function(annotation, index) { | |
| var annotationKey = Object.keys(annotation)[0]; | |
| if (annotationKey === 'error') { | |
| errors.push(annotation.error); | |
| spliceIndexes.push(index); | |
| } | |
| return annotation; | |
| }); | |
| spliceIndexes.forEach(function(spliceIndex, index) { | |
| if (index > 0) { | |
| spliceIndex -= index; | |
| } | |
| annotations.splice(spliceIndex, 1); | |
| }); | |
| annotations.push({ | |
| errors: errors | |
| }); | |
| return annotations; | |
| } | |
| function flattenAnnotations(annotations) { | |
| return extend.apply(null, annotations); | |
| } | |
| function formatAnnotationBuilder(type) { | |
| return function(annotation) { | |
| var formatMethodMap = { | |
| errors: Vision.formatError_, | |
| faceAnnotations: Vision.formatFaceAnnotation_, | |
| imagePropertiesAnnotation: Vision.formatImagePropertiesAnnotation_, | |
| labelAnnotations: Vision.formatEntityAnnotation_, | |
| landmarkAnnotations: Vision.formatEntityAnnotation_, | |
| logoAnnotations: Vision.formatEntityAnnotation_, | |
| safeSearchAnnotation: Vision.formatSafeSearchAnnotation_, | |
| textAnnotations: Vision.formatEntityAnnotation_ | |
| }; | |
| return formatMethodMap[type](annotation, options); | |
| }; | |
| } | |
| function decorateAnnotations(annotations) { | |
| if (is.empty(annotations)) { | |
| // No annotations found, represent as an empty result set. | |
| return []; | |
| } | |
| for (var annotationType in annotations) { | |
| if (annotations.hasOwnProperty(annotationType)) { | |
| var annotationGroup = arrify(annotations[annotationType]); | |
| var formattedAnnotationGroup = annotationGroup | |
| .map(formatAnnotationBuilder(annotationType)); | |
| // An annotation can be singular, e.g. SafeSearch. It is either | |
| // violent or not. Unlike face detection, where there can be | |
| // multiple results. | |
| // | |
| // Be sure the original type (object or array) is preserved and | |
| // not wrapped in an array if it wasn't originally. | |
| if (!is.array(annotations[annotationType])) { | |
| formattedAnnotationGroup = formattedAnnotationGroup[0]; | |
| } | |
| delete annotations[annotationType]; | |
| var typeShortName = typeRespNameToShortName[annotationType]; | |
| annotations[typeShortName] = formattedAnnotationGroup; | |
| } | |
| } | |
| if (types.length === 1) { | |
| // Only a single detection type was asked for, so no need to box in | |
| // the results. Make them accessible without using a key. | |
| var key = Object.keys(annotations)[0]; | |
| annotations = annotations[key]; | |
| } | |
| return annotations; | |
| } | |
| }); | |
| }); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment