As christoph-rackwitz suggest in his link I want an inscribed rectangle . I eventually gave some good instructions to ChatGPT and it came up with an answer. I've included it in the app and tested it on several image pairs and it crops them effectively. Here is the relevant code:
def find_corners(image):
# Finds the four extreme corners of the valid image region (non-black pixels).
coords = np.column_stack(np.where(np.any(image > 0, axis=2)))
top_left = coords[np.argmin(np.sum(coords, axis=1))]
bot_left = coords[np.argmax(coords[:, 0] - coords[:, 1])]
bot_right = coords[np.argmax(np.sum(coords, axis=1))]
top_right = coords[np.argmax(coords[:, 1] - coords[:, 0])]
return top_left, bot_left, bot_right, top_right
def get_overlap_region(imageL, imageR):
#Compute the largest overlapping area after alignment.
left_corners = find_corners(imageL)
right_corners = find_corners(imageR)
left_TL, left_BL, left_BR, left_TR = left_corners
right_TL, right_BL, right_BR, right_TR = right_corners
top_limit = max(left_TL[0], left_TR[0], right_TL[0], right_TR[0])
bot_limit = min(left_BL[0], left_BR[0], right_BL[0], right_BR[0])
left_limit = max(left_TL[1], left_BL[1], right_TL[1], right_BL[1])
right_limit = min(left_TR[1], left_BR[1], right_TR[1], right_BR[1])
return imageL[top_limit:bot_limit, left_limit:right_limit], imageR[top_limit:bot_limit, left_limit:right_limit]
-----
imageLaligned, imageRaligned = find_alignment(imageL, imageR)
imageLcropped, imageRcropped = get_overlap_region(imageLaligned, imageRaligned)
cropH = min(imageLcropped.shape[0], imageRcropped.shape[0])
cropW = min(imageLcropped.shape[1], imageRcropped.shape[1])
imageLcropped = imageLcropped[:cropH, :cropW]
imageRcropped = imageRcropped[:cropH, :cropW]