Public
Edited
Dec 3
14 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// The images are detected in an apparently random fashion.
// This bit of code uses a heuristic approach to the travelling salesman
// problem to display the faces in a less chaotic fashion.

order = {
if (face_info.faces.length > 0) {
const tsp = new TravelingSalesman();
tsp.maxCycles = 100;

let points = face_info.faces.map((o, i) => {
let pt = [o._box._x + o._box._width / 2, o._box._y + o._box._height / 2];
pt.index = i;
return pt;
});

tsp.createFirstNeuron();
tsp.cities = points.map((d, i) => ({ x: d[0], y: d[1] }));
var done, pos;
do {
done = tsp.surveyRun();
let n = tsp.neurons.start;
pos = [[n.x, n.y]];
for (let i = 0; i < tsp.neurons.length; i++) {
n = n.right;
pos.push([n.x, n.y]);
}
} while (!done && tsp.cycle < tsp.maxCycles);

let D = d3.Delaunay.from(pos);
let order = points.map((d) => D.find(d[0], d[1]));
order = points
.map((pt) => pt) // Copy the points since the next sort reorders them
.sort((a, b) => order[a.index] - order[b.index])
.map((pt) => pt.index);

// This bit just reorders so that John Lennon shows up first on the
// Sgt Pepper tour - at least on my Mac.
let start = order.slice(0, 13);
let fin = order.slice(13);
order = fin.concat(start);

return order[0] === -1 ? this : order;
} else {
return [];
}
}
Insert cell
// Detect the faces and store some info about the image
face_info = {
let im = await file.image();
let im_width = im.width;
let im_height = im.height;
const options = new faceapi.SsdMobilenetv1Options({
minConfidence: 0.4
});
let faces = await faceapi.detectAllFaces(im, options);
return { width: im_width, height: im_height, faces: faces };
}
Insert cell
file = {
if (input_file) {
return input_file;
} else {
return selected_file.attachment;
}
}
Insert cell
images = [
{
// https://en.wikipedia.org/wiki/Yalta_Conference#/media/File:Yalta_Conference_(Churchill,_Roosevelt,_Stalin)_(B&W).jpg
name: "Yalta",
attachment: FileAttachment("Yalta.jpg"),
comment: `<p>The <a href="https://en.wikipedia.org/wiki/Yalta_Conference">Yalta conference</a> was arguably one of the most important meetings of the 20th century. This image shows the three leaders in attendance.<p>`
},
{
// https://en.wikipedia.org/wiki/1968_Olympics_Black_Power_salute#/media/File:John_Carlos,_Tommie_Smith,_Peter_Norman_1968cr.jpg
name: "Olympic black power",
attachment: FileAttachment("John_Carlos_Tommie_Smith_black_power.jpg"),
comment: `<p>One of the great moments in the history of the Olympics and Civil Rights was in Mexico City. Tommie Smith became the first person to run 200 meters in under 20 seconds, yet he's remembered more for his Black Power salute.</p> <p>This image also shows that the software can detect faces in profile.<p>`
},
{
// https://beatles.fandom.com/wiki/Category:Copyrighted_free_use_files
name: "Sgt. Pepper",
attachment: FileAttachment("sgt-pepper.jpg"),
comment: `<p>The Sgt. Pepper album cover seems like a good challenge. <a href="https://en.wikipedia.org/wiki/List_of_images_on_the_cover_of_Sgt._Pepper%27s_Lonely_Hearts_Club_Band">According to Wikipedia</a>, there are 71 faces on the cover, though some are obscured and/or not photographs. The software captures 54 faces on my Macintosh, though that number seems to be platform dependent.<p>`
}
]
Insert cell
Insert cell
h = w / aspect;
Insert cell
aspect = face_info.width / face_info.height
Insert cell
w = width < 700 ? width : 700
Insert cell
Insert cell
// From https://observablehq.com/@radames/face-api-js-face-landmarks-with-d3-geo
faceapi = {
const f = await import("@vladmandic/face-api/dist/face-api.esm.js");

await f.loadSsdMobilenetv1Model(
"https://cdn.jsdelivr.net/gh/vladmandic/face-api@1.4.1/model/"
);
return f;
}
Insert cell
import { TravelingSalesman } from "@fil/som-tsp"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more