# Images Are Just Arrays

*Task 5 of 6 · [Data In, Data Out](https://gpu.rocks/learn/data-in-data-out-42b68d01.md) · GPU.js Learn*

Task 3 painted pixels. But an image doesn't have to *stay* an image: in this
course an image is a nested array — `photo[y][x]` is an `[r, g, b, a]`
pixel with channels 0–1 — and a kernel can read it like any other array argument.

Drop `graphical: true`, and the same per-pixel indexing produces
**numbers** instead of colors: a measurement per pixel, ready for JavaScript.

**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]`.

## Figures

- **drop graphical: true and a pixel is just four numbers**

## Goal

**Goal:** compute a 64×64 brightness map of `photo` — each cell
the average of that pixel's red, green and blue channels.

## Requirements

- Keep the kernel numeric — no `graphical: true`, output `[64, 64]`
- Read this thread's pixel: `photo[this.thread.y][this.thread.x]`
- Return `(r + g + b) / 3`

## Hint 1 — same indexing as task 3

The pixel lookup is identical to the grayscale task — only the ending changes:
`return` a number instead of calling `this.color()`.

## Hint 2 — the average

```js
const pixel = photo[this.thread.y][this.thread.x];
return (pixel[0] + pixel[1] + pixel[2]) / 3;
```

## Same idea elsewhere

Treating an image as a data grid is how real pipelines work: computer-vision
pre-processing, depth-map filtering, scientific imaging. In CUDA/WebGPU this is a compute
pass sampling a texture and writing to a plain buffer.

## Starter code

```js
// An image is a nested array: photo[y][x] → [r, g, b, a], all 0–1.
const gpu = new GPU({ mode });

const brightness = gpu.createKernel(function (photo) {
  const pixel = photo[this.thread.y][this.thread.x];
  // TODO: return the average of the red, green and blue channels
  return pixel[0];
}, { output: [64, 64] });

const map = await brightness(photo);
console.log('top-left brightness:', map[0][0]);
```

---

Interactive version: https://gpu.rocks/learn/data-in-data-out-42b68d01/5

[Previous task](https://gpu.rocks/learn/data-in-data-out-42b68d01/4.md) · [Next task](https://gpu.rocks/learn/data-in-data-out-42b68d01/6.md)
