Hi, this is Alex from DEV STORIES DOT EU. scikit-image: The AI Image Pipeline, episode 1 of 5. Before a deep learning model can recognize a face, it must digest a grid of numbers. If you feed that grid in the wrong order, your model learns nothing, and your processing slows to a crawl. The AI Image Pipeline:
NumPy at the Core is the solution to structuring that grid correctly.
When you load an image using scikit-image, you do not get a proprietary image object. You get a standard N-dimensional array, known as an ndarray. An image is simply a matrix of pixels. Because it is a plain NumPy array, you can use any standard operation to slice, mask, or manipulate the image data directly.
Here is the key insight. The way scikit-image indexes these arrays trips up a lot of developers. In standard geometry, you use x and y coordinates, where x is horizontal and y is vertical. scikit-image abandons this for matrix notation. The first index is the row, which corresponds to the vertical position. The second index is the column, which corresponds to the horizontal position. If you have a color image, the third index is the color channel. A standard two-dimensional color image is actually a three-dimensional array ordered as row, column, channel.
Suppose you are preparing a batch of color images to feed into a Convolutional Neural Network. Your network expects a specific shape. If your image is 256 pixels high and 256 pixels wide with red, green, and blue channels, the shape of a single image is 256, 256, 3. But a batch of these images adds a fourth dimension at the beginning, representing the number of images.
When you apply scikit-image functions to this data, the function needs to know which dimension holds the color values so it does not process them as spatial data. This is handled by the channel axis argument. By setting the channel axis argument to negative one, you tell the function that the color channels are always in the last dimension of the array. This ensures the function targets the correct color data, regardless of whether you pass it a single image or a large batch with extra spatial dimensions.
This brings us to memory. This is the part that matters for processing speed. NumPy arrays are stored in contiguous blocks of memory, using a C-like order by default. This means the last dimension in the array shape changes fastest in physical memory. For our standard image array of row, column, channel, the individual color channels for a single pixel sit right next to each other in your hardware RAM.
If you write custom code to loop over these pixels, you must respect this memory layout. The rule is absolute: the rightmost dimension of your array should be processed in the innermost loop. You iterate over rows in the outer loop, then columns, then channels on the inside. If you reverse this and loop over rows on the inside, you force the CPU to jump back and forth across fragmented memory addresses. This destroys cache locality and makes your code run significantly slower.
The most critical thing to remember is that scikit-image does not use horizontal and vertical coordinates; it uses strict matrix indexing of row, column, and channel, and matching your loops to that exact memory order is what keeps your data pipeline fast.
If you want to help keep this podcast going, you can support the show by searching for DevStoriesEU on Patreon. That is all for this one. Thanks for listening, and keep building!