Published
Edited
May 14, 2021
1 fork
Importers
57 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Kx = [-1, 0, +1, -2, 0, +2, -1, 0, +1]
Insert cell
Ky = [-1, -2, -1, 0, 0, 0, +1, +2, +1]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function* convolveRgb1(context, K, input = context.getImageData(0, 0, width, height)) {
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let r = 0;
let g = 0;
let b = 0;
for (let xk = y - 1, j = 0; xk <= y + 1; ++xk) {
for (let yk = x - 1; yk <= x + 1; ++yk, ++j) {
let i = (xk * width + yk) << 2;
r += input.data[i + 0] * K[j];
g += input.data[i + 1] * K[j];
b += input.data[i + 2] * K[j];
}
}
output.data[i + 0] = (r + 255) / 2;
output.data[i + 1] = (g + 255) / 2;
output.data[i + 2] = (b + 255) / 2;
output.data[i + 3] = 255;
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
Insert cell
function* convolveRgb2(context, Kx, Ky, input = context.getImageData(0, 0, width, height)) {
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let rx = 0, ry = 0;
let gx = 0, gy = 0;
let bx = 0, by = 0;
for (let yk = y - 1, j = 0; yk <= y + 1; ++yk) {
for (let xk = x - 1; xk <= x + 1; ++xk, ++j) {
let i = (yk * width + xk) << 2;
rx += input.data[i + 0] * Kx[j];
ry += input.data[i + 0] * Ky[j];
gx += input.data[i + 1] * Kx[j];
gy += input.data[i + 1] * Ky[j];
bx += input.data[i + 2] * Kx[j];
by += input.data[i + 2] * Ky[j];
}
}
output.data[i + 0] = Math.hypot(rx, ry);
output.data[i + 1] = Math.hypot(gx, gy);
output.data[i + 2] = Math.hypot(bx, by);
output.data[i + 3] = 255;
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
function rgb_lrgb1(v) {
return (v /= 255) <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
}
Insert cell
function lrgb_rgb1(v) {
return (v <= 0.0031308 ? 12.92 * v : 1.055 * (v ** (1 / 2.4)) - 0.055) * 255;
}
Insert cell
Insert cell
kr = 0.2126
Insert cell
kg = 0.7152
Insert cell
kb = 0.0722
Insert cell
function gray(r, g, b) {
return lrgb_rgb1(kr * rgb_lrgb1(r) + kg * rgb_lrgb1(g) + kb * rgb_lrgb1(b));
}
Insert cell
Insert cell
grayscale = {
const context = DOM.context2d(width, height, 1);
context.canvas.style = "max-width: 100%;";
context.drawImage(image, 0, 0, width, height);
const input = context.getImageData(0, 0, width, height);
const output = context.createImageData(width, height);
for (let y = 0, i = 0; y < height; ++y) {
for (let x = 0; x < width; ++x, i += 4) {
const r = rgb_lrgb1(input.data[i + 0]);
const g = rgb_lrgb1(input.data[i + 1]);
const b = rgb_lrgb1(input.data[i + 2]);
const a = lrgb_rgb1(kr * r + kg * g + kb * b);
output.data[i + 0] =
output.data[i + 1] =
output.data[i + 2] = a;
output.data[i + 3] = 255;
}
}
context.putImageData(output, 0, 0);
return context.canvas;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function* convolveY1(context, K, input = context.getImageData(0, 0, width, height)) {
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let c = 0;
for (let xk = y - 1, j = 0; xk <= y + 1; ++xk) {
for (let yk = x - 1; yk <= x + 1; ++yk, ++j) {
let i = (xk * width + yk) << 2;
c += input.data[i] * K[j];
}
}
output.data[i + 0] =
output.data[i + 1] =
output.data[i + 2] = (c + 255) / 2;
output.data[i + 3] = 255;
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
function* convolveY1a(context, K, input = context.getImageData(0, 0, width, height)) {
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let c = 0;
for (let xk = y - 1, j = 0; xk <= y + 1; ++xk) {
for (let yk = x - 1; yk <= x + 1; ++yk, ++j) {
let i = (xk * width + yk) << 2;
c += input.data[i] * K[j];
}
}
output.data[i + 0] = Math.max(c, 0);
output.data[i + 1] =
output.data[i + 2] = Math.max(-c, 0);
output.data[i + 3] = 255;
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
Insert cell
function* convolveY2(context, Kx, Ky, input = context.getImageData(0, 0, width, height)) {
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let cx = 0, cy = 0;
for (let yk = y - 1, j = 0; yk <= y + 1; ++yk) {
for (let xk = x - 1; xk <= x + 1; ++xk, ++j) {
let i = (yk * width + xk) << 2;
cx += input.data[i] * Kx[j];
cy += input.data[i] * Ky[j];
}
}
output.data[i + 0] =
output.data[i + 1] =
output.data[i + 2] = Math.hypot(cx, cy);
output.data[i + 3] = 255;
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
Insert cell
function* convolveTheta(context, Kx, Ky) {
const input = context.getImageData(0, 0, width, height);
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let ax = 0, ay = 0;
for (let yk = y - 1, j = 0; yk <= y + 1; ++yk) {
for (let xk = x - 1; xk <= x + 1; ++xk, ++j) {
let i = (yk * width + xk) << 2;
ax += input.data[i] * Kx[j];
ay += input.data[i] * Ky[j];
}
}
const t = Math.atan2(ay, ax) / (2 * Math.PI);
const {r, g, b} = d3.rgb(d3.interpolateSinebow(t));
output.data[i + 0] = r;
output.data[i + 1] = g;
output.data[i + 2] = b;
output.data[i + 3] = 255;
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
Insert cell
function* convolveThetaAlpha(context, Kx, Ky) {
const input = context.getImageData(0, 0, width, height);
const output = context.createImageData(width, height);
yield context.canvas;
for (let y = 1, i = (width + 1) * 4; y < height - 1; ++y, i += 8) {
for (let x = 1; x < width - 1; ++x, i += 4) {
let ax = 0, ay = 0;
for (let yk = y - 1, j = 0; yk <= y + 1; ++yk) {
for (let xk = x - 1; xk <= x + 1; ++xk, ++j) {
let i = (yk * width + xk) << 2;
ax += input.data[i] * Kx[j];
ay += input.data[i] * Ky[j];
}
}
const t = Math.atan2(ay, ax) / (2 * Math.PI);
const {r, g, b} = d3.rgb(d3.interpolateSinebow(t));
output.data[i + 0] = r;
output.data[i + 1] = g;
output.data[i + 2] = b;
output.data[i + 3] = Math.hypot(ax, ay);
}
context.putImageData(output, 0, 0, 0, y, width, 1);
yield context.canvas;
}
}
Insert cell
Insert cell
image = Object.assign(await FileAttachment("blue.jpg").image(), {style: "max-width: 100%; display: block;"})
Insert cell
function createContext(image) {
const context = DOM.context2d(width, height, 1);
context.canvas.style = "max-width: 100%;";
context.drawImage(image, 0, 0, width, height);
return context;
}
Insert cell
width = 975
Insert cell
height = Math.round(width / image.naturalWidth * image.naturalHeight)
Insert cell
d3 = require("d3-color@1", "d3-scale-chromatic@1")
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