Skip to content

Instantly share code, notes, and snippets.

@stephenplusplus
Created May 23, 2016 14:31
Show Gist options
  • Save stephenplusplus/aa0c82b4939e5901680e41c9a89e8c03 to your computer and use it in GitHub Desktop.
Save stephenplusplus/aa0c82b4939e5901680e41c9a89e8c03 to your computer and use it in GitHub Desktop.
Vision.prototype.detect
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