You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python OpenCV对收据图像去歪斜并获取新边界框?

How to Deskew a Receipt Image and Update Bounding Box Coordinates

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 minAreaRect angle 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 09:22:44