如何用OpenCV提取A4扫描件中任意朝向的最大类矩形支票?
非AI模型提取A4扫描图中倾斜支票的最优方案
问题分析
你当前的代码存在三个核心问题:
- 未对矩形轮廓的尺寸、比例做过滤,导致所有微小四边形都被误提取
- 使用
RETR_TREE模式会获取过多层级的内部小轮廓 - 没有针对倾斜矩形的透视校正处理,无法输出正立的支票图像
优化解决方案
核心思路
- 预处理图像以减少噪声干扰,强化支票边缘
- 筛选符合支票尺寸、比例特征的四边形轮廓
- 对倾斜轮廓做透视变换,输出校正后的正立支票
完整代码实现
import cv2 import numpy as np from google.colab.patches import cv2_imshow def extract_cheque(image_path): # 读取原始图像 image = cv2.imread(image_path) orig_image = image.copy() img_height, img_width = image.shape[:2] # 预处理:模糊降噪+边缘检测 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) edges = cv2.Canny(blurred, 30, 150) # 形态学膨胀:连接断裂的支票边缘 dilate_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) dilated_edges = cv2.dilate(edges, dilate_kernel, iterations=2) # 只提取最外层大轮廓,跳过内部小轮廓 contours, _ = cv2.findContours(dilated_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按轮廓面积从大到小排序,优先处理大目标 contours = sorted(contours, key=cv2.contourArea, reverse=True) for contour in contours: contour_area = cv2.contourArea(contour) # 过滤过小轮廓:只保留占图像面积1/20以上的区域 if contour_area < (img_height * img_width) / 20: continue # 多边形逼近,提取四边形轮廓 epsilon = 0.02 * cv2.arcLength(contour, True) approx_poly = cv2.approxPolyDP(contour, epsilon, True) if len(approx_poly) == 4: # 校验宽高比:匹配支票典型比例(1.5-2.5,旋转后为0.4-0.67) x, y, rect_w, rect_h = cv2.boundingRect(approx_poly) aspect_ratio = float(rect_w) / rect_h if (1.5 < aspect_ratio < 2.5) or (0.4 < aspect_ratio < 0.67): # 重新排列四点顺序:左上、右上、右下、左下 pts = approx_poly.reshape(4, 2) target_rect = np.zeros((4, 2), dtype="float32") # 通过坐标和与差确定四点位置 coord_sum = pts.sum(axis=1) target_rect[0] = pts[np.argmin(coord_sum)] target_rect[2] = pts[np.argmax(coord_sum)] coord_diff = np.diff(pts, axis=1) target_rect[1] = pts[np.argmin(coord_diff)] target_rect[3] = pts[np.argmax(coord_diff)] # 计算目标矩形的实际尺寸 max_width = int(max(np.linalg.norm(target_rect[0]-target_rect[1]), np.linalg.norm(target_rect[2]-target_rect[3]))) max_height = int(max(np.linalg.norm(target_rect[1]-target_rect[2]), np.linalg.norm(target_rect[3]-target_rect[0]))) # 定义透视变换的目标坐标 dst_coords = np.array([ [0, 0], [max_width - 1, 0], [max_width - 1, max_height - 1], [0, max_height - 1]], dtype="float32") # 执行透视变换,校正倾斜 transform_matrix = cv2.getPerspectiveTransform(target_rect, dst_coords) corrected_cheque = cv2.warpPerspective(orig_image, transform_matrix, (max_width, max_height)) # 显示并返回校正后的支票 cv2_imshow(corrected_cheque) # 可选:保存结果 # cv2.imwrite('corrected_cheque.jpg', corrected_cheque) return corrected_cheque print("未检测到符合条件的支票轮廓") return None # 调用函数处理图像 extract_cheque('/content/img.jpg')
关键优化说明
- 预处理优化:高斯模糊减少噪声干扰,膨胀操作连接支票边缘的断裂部分,避免轮廓被拆分
- 轮廓筛选:使用
RETR_EXTERNAL模式只提取最外层轮廓,结合面积、宽高比过滤,精准定位支票区域 - 透视校正:重新排列四边形顶点顺序,通过透视变换将倾斜支票转换为正立的矩形图像
内容的提问来源于stack exchange,提问作者Sadaf Shafi
相关产品推荐
相关产品推荐

