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

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