Task 5 of 5

Sobel Edge Detection

The payoff: run two convolutions at once. Sobel's Gx filter responds to horizontal change, Gy to vertical change, and the length of that gradient vector — √(gx² + gy²) — is how edge-like the pixel is, whatever the edge's direction.

This is a two-kernel pipeline like the finale of Data In, Data Out: a numeric pass turns the image into a luminance map (written for you), then the Sobel pass reads each map cell's eight neighbors, applies both weight grids, and paints the magnitude. Border pixels have no full neighborhood, so the starter already paints them black — your work lives in the else branch.

Array layout in gpu.js

Image data comes in row-major: image[y][x] is the pixel in row y, column x, and each pixel is an [r, g, b, a] array with channels from 0 to 1. Mind the inversion that catches everyone — sizes are given width-first (output: [width, height]), but indexing runs row-first, so this thread's own pixel is image[this.thread.y][this.thread.x]. Swap those two and you read the transpose of your image. Three-dimensional data follows the same rule: output: [w, h, d] is indexed [z][y][x].

Goal: finish the Sobel kernel — read the 3×3 neighborhood of gray, compute gx and gy with the weights shown in the starter, and paint Math.sqrt(gx * gx + gy * gy) as a gray value.

Requirements

Hint 1 — name the neighborhood

Pull the nine cells into locals first — const tl = gray[y - 1][x - 1]; through const br = gray[y + 1][x + 1]; — then the two weighted sums are easy to read off the grids.

Hint 2 — the two sums
const gx = (tr + 2 * mr + br) - (tl + 2 * ml + bl);

— right column minus left column, middle counted double. gy is the same with rows: (bl + 2 * bm + br) - (tl + 2 * tm + tr).

Hint 3 — the finish
const m = Math.sqrt(gx * gx + gy * gy);
this.color(m, m, m, 1);

— flat areas give 0 (black), sharp edges overshoot 1 and clamp to white.

Same idea elsewhere

Sobel is the hello-world of GPU vision: it opens the OpenCL and CUDA imaging tutorials, camera ISPs run it in silicon, and edge maps feed feature detectors everywhere. Fusing two directional filters into one pass is exactly how you would write it in WGSL or Metal, too.

All tasks in Convolution & Filters

  1. Slide a Window: 1D Convolution
  2. Any Filter, One Kernel
  3. Box Blur: the Window Goes 2D
  4. Sharpen: Negative Weights
  5. Sobel Edge Detection

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.