Public
Edited
Oct 24, 2023
4 forks
21 stars
Insert cell
Insert cell
Insert cell
canvas1 = DOM.canvas(width, height, 1)
Insert cell
update1 = {
const context = canvas1.getContext("2d");
context.drawImage(image, 0, 0);
const data = context.getImageData(0, 0, width, height);
d3.blurImage(data, r);
context.putImageData(data, 0, 0);
return htl.html`<em>Blurred with radius ${r}.`
}
Insert cell
Insert cell
Insert cell
Insert cell
canvas2 = DOM.canvas(width, height, 1)
Insert cell
update2 = {
const context = canvas2.getContext("2d");
context.drawImage(image, 0, 0);
const data = context.getImageData(0, 0, width, height);
d3.blurImage(data, rx, ry);
context.putImageData(data, 0, 0);
return htl.html`<em>Blurred with radii [${rx}, ${ry}].`
}
Insert cell
Insert cell
Insert cell
laplacianCanvas({image, gain: 20, radius: 0.5}) // contours
Insert cell
function laplacian(image, radius) {
const I = image.data;
const L = new Float32Array(I); // copy before blurring; allow negative values
d3.blurImage(image, radius);
for (let i = 0, n = I.length; i < n; ++i) {
if (i % 4 === 3) continue; // ignore the A channel of RGBA
L[i] -= I[i];
}
return L;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
canvas4 = DOM.canvas(width, height, 1)
Insert cell
update4 = laplacianCanvas({image, canvas: canvas4, gain, alpha, radius: rl})
Insert cell
Insert cell
fuzziness = {
const canvas = DOM.canvas(width, height, 1);
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0, width, height);
const L = laplacian(context.getImageData(0, 0, width, height), 0.5);
return [0, 1, 2].map(channel => d3.deviation(L, (d, i) => (i % 4 === channel ? d : NaN)));
}
Insert cell
Insert cell
function laplacianCanvas({
image,
width = image.naturalWidth,
height = image.naturalHeight,
canvas = DOM.canvas(width, height, 1),
gain = 1,
alpha = 0,
radius
}) {
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height);
const L = laplacian(context.getImageData(0, 0, width, height), radius);
const {data: I} = imageData;
for (let i = 0, n = I.length; i < n; ++i) {
if (i % 4 === 3) continue; // skip: ignore the A channel of RGBA
I[i] = (1 - alpha) * 128 + alpha * I[i] + gain * L[i];
}
context.putImageData(imageData, 0, 0);
return canvas;
}
Insert cell
image = FileAttachment("shoreline-emily-carr.png").image({width: 48})
Insert cell
width = image.naturalWidth
Insert cell
height = image.naturalHeight
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