Welcome to the second unit of our course! In our previous unit, we learned how to composite and crop aligned images to create a clean, merged panorama. Now, we are going to build the engine that powers our entire panorama maker.
Our goal is to take all the separate tools we have built or learned about so far — such as finding keypoints, matching features, and estimating geometry — and combine them into a single, reliable function called stitch_pair. This master function will take two raw images, attempt to stitch them, handle any errors gracefully, and return both the final image and a detailed diagnostic report.
Before we start coding, let us briefly recall the sequence of operations required to stitch two images together:
- Preprocessing: Convert images to grayscale so algorithms can process them easily.
- Detection and Computation: Find unique points (keypoints) in both images and describe their surrounding patterns.
- Matching: Pair up matching descriptions between the left and right images.
- Homography Estimation: Use the matched points to figure out the math (a geometric grid) needed to warp one image so that it aligns with the other.
- Warping and Compositing: Stretch the image using our math, overlap the two images, blend them, and crop out any unwanted black borders (as we practiced in the last unit).
We will rely on pre-built helper functions for the heavy math and geometry. This allows us to focus entirely on the integration logic: making sure the pipeline runs smoothly from start to finish.
Let us begin writing our stitch_pair function. Whenever you build a complex pipeline, it is very helpful to keep track of what is happening under the hood. We will do this by creating a report dictionary.
In this initial code, we define our function to accept two images (left and right) and a few settings. Inside, we create the report dictionary.
Notice that we set the initial "status" to "failed". This is a defensive programming practice: we assume the process will fail until it successfully completes every step. The report also holds slots to track how many keypoints we find, how many matches we make, and a space for a "diagnosis" message to help us understand what went wrong if it fails.
Now, let us start processing the images. We will run our preprocessing and feature detection functions and immediately update our report with the results.
At this point, we have matched features. However, calculating a homography (the mathematical alignment grid) requires at least four matched points. If we do not have four points, the math will crash. Let us add a safety check to stop the process early if necessary:
If we have enough matches, we move on to estimating the homography. Because complex geometry can sometimes fail even with enough points, we wrap this in a try-except block to catch any mathematical errors.
Here, we try to calculate the homography. The estimate_homography function also returns inliers (the matches that are geometrically consistent within the RANSAC reprojection threshold, discarding bad matches). This ransac_threshold controls how much alignment error is tolerated: a smaller value requires more precise consistency, while a larger one is more lenient. We calculate the total number of inliers and check if we have fewer than four. If we do, we update the diagnosis and safely return None instead of a broken image.
If our code survives all the safety checks, we have a valid homography! Now we can warp the images and merge them using the composite and crop_black logic we learned in the previous unit.
Before we finish the function, let us define a quick helper function to give us a friendly diagnosis message for successful (or mostly successful) stitches.
This helper looks at the numbers in our report and provides advice. Now, we add the final lines to our stitch_pair function:
If we reach the bottom of the function, everything has worked. We change the "status" to "ok", get our final diagnostic advice, and return the result image alongside our fully populated report.
To make our new stitch_pair function useful, we need a way to run it from our computer's terminal. We can do this by setting up a main execution script that takes inputs from the user.
First, we set up argparse to read the image filenames and settings the user types into the command line.
Next, we pass those read images directly into our stitch_pair function.
If you ran this in your terminal, the printed report output would look something like this:
Finally, we handle the result. If the function returned None, we stop the program. If it succeeded, we save the resulting image to a file and display it on the screen.
Great job! In this lesson, we successfully wrapped our image stitching pipeline into a single, clean function. By adding step-by-step checks, a tracking report, and safe error handling, we transformed a loose collection of scripts into a robust tool. If an image pair lacks enough matching points to stitch safely, our program no longer crashes — it simply explains exactly why it could not complete the job.
Now, it is your turn to put this into action. In the upcoming practice exercises, you will head into the CodeSignal IDE to write this master function yourself, apply the error-handling logic, and test it against real image pairs.
