如何用Python OpenCV对收据图像去歪斜并获取新边界框?
Hey there! Let's fix that skewed receipt and get your bounding box updated. Your initial edge detection was picking up text details instead of the receipt's outer shape—we'll adjust that to focus on the receipt's main contour, calculate the skew angle, correct the image, and finally transform your original bounding box to match the corrected image.
Step 1: Import Required Libraries
First, let's make sure we have all the tools we need (I'll add numpy and matplotlib.pyplot since they're used but missing in your code):
from skimage import io import cv2 import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Polygon
Step 2: Load and Preprocess the Image
We'll load the image, convert it to grayscale, and apply thresholding to get a clean binary image—this helps isolate the receipt from the background:
# Load image image = io.imread('https://i.ibb.co/3WCsVBc/test.jpg') gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) # Binary thresholding (Otsu's method automatically finds the best threshold value) _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
Step 3: Detect the Receipt's Outer Contour
Instead of detecting every small text contour, we'll find the largest contour (which should be the receipt itself):
# Find all contours in the binary image contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Sort contours by area and pick the largest one (the receipt) largest_contour = max(contours, key=cv2.contourArea) # Get the minimum area rectangle that encloses the receipt rect = cv2.minAreaRect(largest_contour) box = cv2.boxPoints(rect) box = np.int0(box)
Step 4: Calculate the Skew Angle
The minAreaRect function returns an angle in the range [-90, 0). We'll convert this to the actual rotation angle needed to straighten the receipt:
angle = rect[2] # Adjust the angle to get the correct rotation direction if angle < -45: angle = 90 + angle # Get image dimensions height, width = gray.shape[:2]
Step 5: Deskew the Image
We'll create a rotation matrix and apply it to both the original image and the grayscale version:
# Calculate rotation matrix around the center of the image center = (width // 2, height // 2) rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0) # Rotate the grayscale image and original color image deskewed_gray = cv2.warpAffine(gray, rotation_matrix, (width, height), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) deskewed_image = cv2.warpAffine(image, rotation_matrix, (width, height), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
Step 6: Transform the Original Bounding Box
Now we need to apply the same rotation to your original bounding box coordinates to get their new positions in the deskewed image:
# Original bounding box coordinates (convert to numpy array for easier processing) original_bbox = np.array([[20, 68], [336, 68], [336, 100], [20, 100]], dtype=np.float32) # Add a column of 1s to apply the rotation matrix (homogeneous coordinates) original_bbox_homogeneous = np.hstack((original_bbox, np.ones((4, 1)))) # Apply the rotation matrix to get the new coordinates new_bbox = rotation_matrix @ original_bbox_homogeneous.T new_bbox = new_bbox.T.astype(np.int0)
Step 7: Visualize the Result
Let's check the deskewed image and the updated bounding box:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(25, 20)) # Original image with bbox ax1.imshow(gray, cmap='Greys_r') rect_original = Polygon(original_bbox, fill=False, linewidth=2, edgecolor='r') ax1.add_patch(rect_original) ax1.set_title('Original Skewed Image') # Deskewed image with updated bbox ax2.imshow(deskewed_gray, cmap='Greys_r') rect_deskewed = Polygon(new_bbox, fill=False, linewidth=2, edgecolor='g') ax2.add_patch(rect_deskewed) ax2.set_title('Deskewed Image with Updated Bounding Box') plt.show() # Print the new bounding box coordinates print("Updated Bounding Box Coordinates:\n", new_bbox)
Key Notes:
- Why we use the largest contour: This ensures we're focusing on the receipt's outer edge instead of individual text lines.
- Angle adjustment: The
minAreaRectangle can be tricky—adjusting for angles < -45 ensures we rotate the image the right way to make it horizontal. - Bounding box transformation: Using homogeneous coordinates lets us apply the same rotation matrix to the bbox points as we did to the image, keeping everything aligned.
This should give you a perfectly straight receipt and the correct coordinates for your original bounding box!
内容的提问来源于stack exchange,提问作者user_12

