Public
Edited
Dec 4, 2023
20 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function project_pixels(pixels, x, y, z, P) {
for (let i = 0; i < P.length; ++i)
P[i] = pixels[4 * i] * x + pixels[4 * i + 1] * y + pixels[4 * i + 2] * z;
return P;
}
Insert cell
Insert cell
advect1 = {
let p, q, orderp, orderq;
const random = d3.randomNormal();
const { hypot } = Math;
return function advect1(values, target, epsilon) {
const l = values.length / 4;
if (!(p && p.length === l)) {
p = new Float32Array(l);
q = new Float32Array(l);
orderp = new Uint32Array(l);
orderq = new Uint32Array(l);
for (let i = 0; i < l; i++) orderp[i] = orderq[i] = i;
}

let x = random(),
y = random(),
z = random();
const norm = 1 / hypot(x, y, z);
x *= norm;
y *= norm;
z *= norm;
p = project_pixels(values, x, y, z, p);
q = project_pixels(target, x, y, z, q);
orderp.sort((i, j) => p[i] - p[j]);
orderq.sort((i, j) => q[i] - q[j]);

let energy = 0;
for (let k = 0; k < orderp.length; k++) {
const i = orderp[k],
j = orderq[k];
const a = q[j] - p[i],
b = a * epsilon;
values[4 * i + 0] += b * x;
values[4 * i + 1] += b * y;
values[4 * i + 2] += b * z;
energy += Math.abs(a);
}

return energy;
};
}
Insert cell
Insert cell
naive = {
await visibility();
// image context
const context = DOM.context2d(w, h, 1),
imagedata = context.getImageData(0, 0, w, h),
{ data } = imagedata;

const [from, to] = [source.data, target.data];

// result context
const ctx = DOM.context2d(width, h);

yield ctx.canvas;
// this both converts to float & slices the array
const values = Float32Array.from(from);
for (let i = 0; i < 100; i++) {
const energy = advect1(values, to, .3);
for (let i = 0; i < data.length; i++) data[i] = values[i];
context.putImageData(imagedata, 0, 0);
ctx.drawImage(context.canvas, 0, 0);
ctx.fillStyle = "white";
ctx.fillText(`${i + 1} steps, ${(energy / w / h).toFixed(2)}`, 10, 10);
if ((i + 1) % 5 === 0) yield ctx.canvas;
}
yield ctx.canvas;
}
Insert cell
Insert cell
// Compute a batch of transformations and apply them at once
advectBatch = {
let orderp, orderq, p, q, batch;
const random = d3.randomNormal();
const { hypot } = Math;

return function advectBatch(values, target, n, epsilon) {
const l = values.length / 4;
if (!(p && p.length === l)) {
p = new Float32Array(l);
q = new Float32Array(l);
batch = new Float32Array(values.length);
orderp = new Uint32Array(l);
orderq = new Uint32Array(l);
for (let i = 0; i < l; i++) orderp[i] = orderq[i] = i;
}
batch.fill(0);

for (let s = 1; s < n; s++) {
let x = random(),
y = random(),
z = random(),
norm = 1 / hypot(x, y, z);
x *= norm;
y *= norm;
z *= norm;
p = project_pixels(values, x, y, z, p);
q = project_pixels(target, x, y, z, q);
orderp.sort((i, j) => p[i] - p[j]);
orderq.sort((i, j) => q[i] - q[j]);

for (let k = 0; k < l; k++) {
const i = orderp[k],
j = orderq[k];
const b = q[j] - p[i];
batch[4 * i + 0] += b * x;
batch[4 * i + 1] += b * y;
batch[4 * i + 2] += b * z;
}
}

let energy = 0;
for (let i = 0; i < batch.length; i++) {
values[i] += batch[i] * epsilon;
energy += Math.abs(batch[i]);
}

return energy;
};
}
Insert cell
Insert cell
Insert cell
transfered = {
const batchSize = 8;

// image context
const context = DOM.context2d(w, h, 1),
c = context.canvas,
imagedata = context.getImageData(0, 0, w, h),
{ data } = imagedata;

const [from, to] = [source.data, target.data];

// this both converts to float & slices the array
const values = Float32Array.from(from);
c.step = 0;
c.batchSize = batchSize;
do {
c.energy = advectBatch(values, to, batchSize, .3 / batchSize) / w / h;
for (let i = 0; i < data.length; i++) data[i] = Math.round(values[i]);
context.putImageData(imagedata, 0, 0);
c.step++;
yield c;
} while (!(c.energy < batchSize / 2));
yield c;
}
Insert cell
Insert cell
W0 = 1280
Insert cell
W1 = 1024
Insert cell
w = W0 / ratio
Insert cell
h = W1 / ratio
Insert cell
// returns the pixels as r,g,b,a,r,g,b,a,r,g,b,a…
pixelData = src =>
d3.image(src, { crossOrigin: "anonymous" }).then(d => {
const context = DOM.context2d(w, h, 1),
canvas = context.canvas;
context.drawImage(d, 0, 0, w, h);
canvas.value = context.getImageData(0, 0, w, h);
return canvas;
})
Insert cell
source = swapTarget ? image2 : image1
Insert cell
target = swapTarget ? image1 : image2
Insert cell
url1 = "https://rawcdn.githack.com/dcoeurjo/transport-optimal-gdrigrv-11-2020/5507227c7bc569f524069bb2980fcfc72139c1ab/pexelA-0.png"
Insert cell
viewof image1 = pixelData(url1)
Insert cell
url2 = "https://rawcdn.githack.com/dcoeurjo/transport-optimal-gdrigrv-11-2020/5507227c7bc569f524069bb2980fcfc72139c1ab/pexelB-0.png"
Insert cell
viewof image2 = pixelData(url2)
Insert cell
d3 = require("d3@6")
Insert cell
import { checkbox, select } from "@jashkenas/inputs"
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more