diff --git a/test/saliency/README.md b/test/saliency/README.md deleted file mode 100644 index 580d7f24..00000000 --- a/test/saliency/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Crop strategy accuracy - -1. Download the [MSRA Salient Object Database](http://research.microsoft.com/en-us/um/people/jiansun/SalientObject/salient_object.htm) (101MB). -2. Extract each image and its median human-labelled salient region. -3. Generate a test report of percentage deviance of top and left edges for each crop strategy, plus a naive centre gravity crop as "control". - -```sh -git clone https://github.com/lovell/sharp.git -cd sharp/test/saliency -./download.sh -node report.js -python -m SimpleHTTPServer -``` - -The test report will then be available at -http://localhost:8000/report.html diff --git a/test/saliency/download.sh b/test/saliency/download.sh deleted file mode 100755 index 74784472..00000000 --- a/test/saliency/download.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# Fetch and parse the MSRA Salient Object Database 'Image set B' -# http://research.microsoft.com/en-us/um/people/jiansun/salientobject/salient_object.htm - -if [ ! -d Image ]; then - if [ ! -f ImageB.zip ]; then - echo "Downloading 5000 images (101MB)" - curl -O http://research.microsoft.com/en-us/um/people/jiansun/salientobject/ImageSetB/ImageB.zip - fi - unzip ImageB.zip -fi - -if [ ! -d UserData ]; then - if [ ! -f UserDataB.zip ]; then - echo "Downloading human-labelled regions" - curl -O http://research.microsoft.com/en-us/um/people/jiansun/salientobject/ImageSetB/UserDataB.zip - fi - unzip UserDataB.zip -fi - -if [ ! -f userData.json ]; then - echo "Processing human-labelled regions" - node userData.js -fi diff --git a/test/saliency/humanae/download.js b/test/saliency/humanae/download.js deleted file mode 100644 index e3d07ddb..00000000 --- a/test/saliency/humanae/download.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 - -'use strict'; - -const fs = require('fs'); -const request = require('request'); -const tumblr = require('tumblr.js'); - -const client = tumblr.createClient({ - consumer_key: '***', - consumer_secret: '***' -}); - -const fetchImages = function (offset) { - console.log(`Fetching offset ${offset}`); - client.posts('humanae', { - type: 'photo', - offset: offset - }, function (err, response) { - if (err) throw err; - if (response.posts.length > 0) { - response.posts.forEach((post) => { - const url = post.photos[0].alt_sizes - .filter((image) => image.width === 100) - .map((image) => image.url)[0]; - const filename = `./images/${post.id}.jpg`; - try { - fs.statSync(filename); - } catch (err) { - if (err.code === 'ENOENT') { - request(url).pipe(fs.createWriteStream(filename)); - } - } - }); - fetchImages(offset + 20); - } - }); -}; -fetchImages(0); diff --git a/test/saliency/humanae/package.json b/test/saliency/humanae/package.json deleted file mode 100644 index f436f5a2..00000000 --- a/test/saliency/humanae/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "sharp-crop-strategy-attention-model-humanae", - "version": "0.0.1", - "private": true, - "dependencies": { - "request": "^2.75.0", - "tumblr.js": "^1.1.1" - } -} diff --git a/test/saliency/humanae/tone.js b/test/saliency/humanae/tone.js deleted file mode 100644 index 7081614a..00000000 --- a/test/saliency/humanae/tone.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 - -'use strict'; - -const fs = require('fs'); -const childProcess = require('child_process'); - -const a = []; -const b = []; - -fs.readdirSync('./images') - .filter((file) => file.endsWith('.jpg')) - .forEach((file) => { - // Extract one pixel, avoiding first DCT block, and return value of A and B channels - const command = `convert ./images/${file}[1x1+8+8] -colorspace lab -format "%[fx:u.g] %[fx:u.b]" info:`; - const result = childProcess.execSync(command, { encoding: 'utf8' }); - const ab = result.split(' '); - a.push(ab[0]); - b.push(ab[1]); - }); - -a.sort((v1, v2) => v1 - v2); -b.sort((v1, v2) => v1 - v2); - -// Convert from 0..1 to -128..128 -const convert = function (v) { - return Math.round(256 * (v - 0.5)); -}; - -const threshold = Math.round(a.length / 100); -console.log(`Trimming lowest/highest ${threshold} for 98th percentile`); - -// Ignore ~2% outliers -console.log(`a ${convert(a[threshold])} - ${convert(a[a.length - threshold])}`); -console.log(`b ${convert(b[threshold])} - ${convert(b[b.length - threshold])}`); diff --git a/test/saliency/report.html b/test/saliency/report.html deleted file mode 100644 index 792d2737..00000000 --- a/test/saliency/report.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - -
- - - diff --git a/test/saliency/report.js b/test/saliency/report.js deleted file mode 100644 index 66534675..00000000 --- a/test/saliency/report.js +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 - -'use strict'; - -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const async = require('async'); -const sharp = require('../../'); - -const crops = { - entropy: sharp.strategy.entropy, - attention: sharp.strategy.attention -}; -const concurrency = os.cpus().length; - -const scores = {}; - -const incrementScore = function (accuracy, crop) { - if (typeof scores[accuracy] === 'undefined') { - scores[accuracy] = {}; - } - if (typeof scores[accuracy][crop] === 'undefined') { - scores[accuracy][crop] = 0; - } - scores[accuracy][crop]++; -}; - -const userData = require('./userData.json'); -const files = Object.keys(userData); - -async.eachLimit(files, concurrency, function (file, done) { - const filename = path.join(__dirname, 'Image', file); - const salientWidth = userData[file].right - userData[file].left; - const salientHeight = userData[file].bottom - userData[file].top; - sharp(filename).metadata(function (err, metadata) { - if (err) console.log(err); - const marginWidth = metadata.width - salientWidth; - const marginHeight = metadata.height - salientHeight; - async.each(Object.keys(crops), function (crop, done) { - async.parallel([ - // Left edge accuracy - function (done) { - if (marginWidth) { - sharp(filename).resize(salientWidth, metadata.height).crop(crops[crop]).toBuffer(function (err, data, info) { - const delta = Math.abs(userData[file].left + info.cropOffsetLeft); - const accuracy = Math.round(marginWidth / (marginWidth + delta) * 100); - incrementScore(accuracy, crop); - done(err); - }); - } else { - done(); - } - }, - // Top edge accuracy - function (done) { - if (marginHeight) { - sharp(filename).resize(metadata.width, salientHeight).crop(crops[crop]).toBuffer(function (err, data, info) { - const delta = Math.abs(userData[file].top + info.cropOffsetTop); - const accuracy = Math.round(marginHeight / (marginHeight + delta) * 100); - incrementScore(accuracy, crop); - done(err); - }); - } else { - done(); - } - } - ], done); - }, done); - }); -}, function () { - const report = []; - Object.keys(scores).forEach(function (accuracy) { - report.push( - Object.assign({ - accuracy: Number(accuracy) - }, scores[accuracy]) - ); - }); - fs.writeFileSync('report.json', JSON.stringify(report, null, 2)); -}); diff --git a/test/saliency/userData.js b/test/saliency/userData.js deleted file mode 100644 index 6284ce61..00000000 --- a/test/saliency/userData.js +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 - -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const userDataDir = 'UserData'; - -const images = {}; - -const median = function (values) { - values.sort(function (a, b) { - return a - b; - }); - const half = Math.floor(values.length / 2); - if (values.length % 2) { - return values[half]; - } else { - return Math.floor((values[half - 1] + values[half]) / 2); - } -}; - -// List of files -fs.readdirSync(userDataDir).forEach(function (file) { - // Contents of file - const lines = fs.readFileSync(path.join(userDataDir, file), { encoding: 'utf-8' }).split(/\r\n/); - // First line = number of entries - const entries = parseInt(lines[0], 10); - // Verify number of entries - if (entries !== 500) { - throw new Error('Expecting 500 images in ' + file + ', found ' + entries); - } - // Keep track of which line we're on - let linePos = 2; - for (let i = 0; i < entries; i++) { - // Get data for current image - const filename = lines[linePos].replace(/\\/, path.sep); - linePos = linePos + 2; - const regions = lines[linePos].split('; '); - linePos = linePos + 2; - // Parse human-labelled regions for min/max coords - const lefts = []; - const tops = []; - const rights = []; - const bottoms = []; - regions.forEach(function (region) { - if (region.indexOf(' ') !== -1) { - const coords = region.split(' '); - lefts.push(parseInt(coords[0], 10)); - tops.push(parseInt(coords[1], 10)); - rights.push(parseInt(coords[2], 10)); - bottoms.push(parseInt(coords[3], 10)); - } - }); - // Add image - images[filename] = { - left: median(lefts), - top: median(tops), - right: median(rights), - bottom: median(bottoms) - }; - } -}); - -// Verify number of images found -const imageCount = Object.keys(images).length; -if (imageCount === 5000) { - // Write output - fs.writeFileSync('userData.json', JSON.stringify(images, null, 2)); -} else { - throw new Error('Expecting 5000 images, found ' + imageCount); -}