Pixel Indexing Convention

In Julia's image processing, we follow the array indexing convention where:

  • Integers represent the center of pixels
  • Arrays use [y,x] indexing (row, column)
  • The top-left pixel is at coordinates [1,1]
  • y increases downward (following matrix convention)
  • x increases rightward

Here's a visualization of the indexing convention for a 4×4 grid, together with the corresponding physical coordinates for a pixel size of 0.1 μm:

Example block output

Each pixel is labeled with its (y,x) index: the top-left pixel is (1,1), y increases downward, and x increases rightward. Dots mark the pixel centers, which sit at integer pixel coordinates — pixel boundaries lie at the half-integers. The highlighted center of pixel (2,3) reads (x, y) = (0.25, 0.15) μm on the physical axes.

Physical units

Following the convention set by SMLMData.jl and used across the ecosystem:

  • All spatial coordinates are in microns
  • Physical space: (0,0) is the top-left corner of the camera
  • Pixel space: (1,1) is the center of the top-left pixel

With pixel size $\Delta$ (μm), pixel coordinates translate to physical coordinates as

\[x_{\text{phys}} = (x_{\text{px}} - 0.5)\,\Delta, \qquad y_{\text{phys}} = (y_{\text{px}} - 0.5)\,\Delta,\]

and back as $x_{\text{px}} = x_{\text{phys}}/\Delta + 0.5$. Pixel boundaries (half-integer pixel coordinates) therefore sit at integer multiples of $\Delta$, and the center of the top-left pixel is at $(0.5\,\Delta, 0.5\,\Delta)$.

SMLMData.jl exports these conversions as pixel_to_physical, physical_to_pixel, and physical_to_pixel_index (see the SMLMData API reference):

using SMLMData

pixel_to_physical(3, 2, 0.1)   # center of pixel [2,3] -> (0.25, 0.15) μm
physical_to_pixel(0.25, 0.15, 0.1)   # -> (3.0, 2.0)