Skip to content
This repository has been archived by the owner on Jan 12, 2021. It is now read-only.

Add support for custom classifiers #67

Closed
wants to merge 20 commits into from
25 changes: 25 additions & 0 deletions processing/analysis/analysis.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,31 @@ function analyzeImage(args, fileName, analyzeCallback) {
}
callback(null);
}));
},
(callback) => {
// Call Classify passing the image in the request
// http://www.ibm.com/watson/developercloud/visual-recognition/api/v3/?curl#classify_an_image
fs.createReadStream(fileName).pipe(
request({
method: 'POST',
url: 'https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify' + // eslint-disable-line
'?api_key=' + args.watsonApiKey +
'&classifier_ids=SewerSpy_880630111' +
'&version=2016-05-20',
headers: {
'Content-Length': fs.statSync(fileName).size
},
json: true
}, (err, response, body) => {
if (err) {
console.log('Custom Keywords', err);
} else if (body.images && body.images.length > 0) {
if (body.images[0].classifiers && body.images[0].classifiers.length > 0){
analysis.custom_keywords = body.images[0].classifiers[0].classes;
}
}
callback(null);
}));
}
],
(err) => {
Expand Down
25 changes: 25 additions & 0 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ app.get('/api/videos/:id', (req, res) => {
// These maps will be used to decide which tags/faces to keep for the video summary
let peopleNameToOccurrences = {};
let keywordToOccurrences = {};
let customKeywordToOccurrences = {};

console.log('Sorting analysis for video', video._id);
images.forEach((image) => {
Expand Down Expand Up @@ -345,6 +346,19 @@ app.get('/api/videos/:id', (req, res) => {
keyword.timecode = image.frame_timecode;
});
}

if (image.analysis && image.analysis.custom_keywords) {
image.analysis.custom_keywords.forEach((keyword) => {
if (!customKeywordToOccurrences[keyword.class]) {
customKeywordToOccurrences[keyword.class] = [];
}
customKeywordToOccurrences[keyword.class].push(keyword);
keyword.image_id = image._id;
keyword.image_url = `${req.protocol}://${req.hostname}/images/image/${image._id}.jpg`;
keyword.timecode = image.frame_timecode;
});
}

});

// Filter a list of occurrences according to the minimum requirements
Expand Down Expand Up @@ -415,12 +429,23 @@ app.get('/api/videos/:id', (req, res) => {
});
// remove the color tags from the overview, they are not interesting in this context
keywordToOccurrences = keywordToOccurrences.filter(keyword => !keyword.class.endsWith(' color'));

// filtering custom keywords
console.log('Filtering custom keywords for video', video._id);
customKeywordToOccurrences = filterOccurrences(customKeywordToOccurrences, {
score: label => label.score,
minimumOccurrence: options.minimumKeywordOccurrence,
minimumScore: options.minimumKeywordScore,
minimumScoreOccurrence: options.minimumKeywordScoreOccurrence,
maximumOccurrenceCount: options.maximumKeywordCount
});

callback(null, {
video,
images,
face_detection: peopleNameToOccurrences,
image_keywords: keywordToOccurrences,
custom_keywords: customKeywordToOccurrences,
});
},
// get the video transcript
Expand Down
9 changes: 9 additions & 0 deletions web/public/routes/home/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ <h4>Image Keywords</h4>
class="tag tag-keyword">{{keyword.class}} {{keyword.score | formatPercent}}%</span></li>
</ul>
</div>
<div flex class="entry-tags">
<h4>Custom Keywords</h4>
<span class="no-tag" ng-if="!image.analysis.custom_keywords">No data yet</span>
<span class="no-tag" ng-if="image.analysis.custom_keywords.length == 0">No custom tag detected</span>
<ul class="entry-taglist">
<li ng-repeat="keyword in image.analysis.custom_keywords" class="entry-tag"><span
class="tag tag-keyword">{{keyword.class}} {{keyword.score | formatPercent}}%</span></li>
</ul>
</div>
<div flex class="entry-faces">
<h4>Face Detection</h4>
<span class="no-tag" ng-if="!image.analysis.face_detection">No data yet</span>
Expand Down
4 changes: 4 additions & 0 deletions web/public/routes/video/video.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
return image.analysis.image_keywords.find(function(keyword) {
return keyword.class === tagName;
});
case 'custom_keywords':
return image.analysis.custom_keywords.find(function(keyword) {
return keyword.class === tagName;
});
}
}
return false;
Expand Down
9 changes: 9 additions & 0 deletions web/public/routes/video/video.html
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,15 @@ <h4>Image Keywords</h4>
ng-if="!controller.showMoreKeywords">and {{controller.data.selectedSummary.image_keywords.length - 15}} more...</span><span ng-if="controller.showMoreKeywords">show less</span></li>
</ul>
</div>

<div>
<h4>Custom Keywords</h4>
<ul class="entry-taglist">
<li ng-repeat="keyword in controller.data.selectedSummary.custom_keywords" class="entry-tag"><span
ng-click="controller.selectImageWithTag('custom_keywords', keyword.class)"
class="tag tag-keyword">{{keyword.class}} {{keyword.score | formatPercent}}%</span></li>
</ul>
</div>

<div ng-if="controller.isVideo() && controller.data.summary.audio.analysis.nlu.keywords">
<h4>Audio Keywords</h4>
Expand Down