Milestone 2 of 8
Implement coordinate-safe crop and flips
Apply half-open row and column bounds, reverse one named axis at a time, predict corners and shapes, and prove every returned array is independent.
Cropping and flipping are small operations, but an off-by-one coordinate can move every pixel. Use one coordinate convention and make it visible.
Goal
Implement half-open row and column crops and both axis flips while preserving the channel axis, dtype, values, and source array.
Operations
For an image of shape (height, width, channels), implement:
crop(image, top, left, bottom, right)
rows = top:bottom
columns = left:right
Require integer, non-boolean coordinates with
0 <= top < bottom <= height and 0 <= left < right <= width.
flip_left_right reverses columns. flip_top_bottom reverses rows. Every
operation returns an independent uint8 array.
Deliverables
Implement the operations in src/operations.py. Save hand-check tables for a
small gradient and checker pattern, including input shape, output shape, and
corner pixels. Keep a crop's half-open coordinates in its stage record.
Checks
Check a one-pixel crop, full-image crop, narrow crop, top-left crop, and bottom-right crop. Predict output shapes and corner values before running the code. Reject negative, reversed, outside, non-integer, and boolean bounds.
Apply each flip twice and compare with the original. Check grayscale and RGB images, preserve the length-one channel axis, and verify that source arrays and their memory do not change.
Workspace
Keep crop and flip implementations and their pure-operation checks in
src/operations.py. Do not add channel selection or brightness yet.
Hints
HintThe upper bound is excluded
top=1, bottom=3
contains rows 1 and 2. Write the selected coordinates before checking pixels.HintFlips have simple landmarks
Review
Choose one cropped checker pattern and explain its top-left output pixel from the source coordinate. Why is “crop and then flip” a different plan from “flip and then crop”?
How to check your work
Checks compare bounds, shapes, corner pixels, and source immutability with the tiny fixtures. These operations change positions, not the pixel value range.