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

使用OpenCV提取图像矩形轮廓时触发AxisError的原因排查

OpenCV提取矩形区域触发AxisError的原因及解决办法

我最近在用Python和OpenCV做图像矩形区域提取(比如文档、护照照片这类),大部分图像都能正常运行,但处理某张特定图像时,突然抛出了这个错误:

axis = normalize_axis_index(axis, nd) numpy.core._internal.AxisError: axis 1 is out of bounds for array of dimension 1

报错的代码段是这段循环轮廓的逻辑:

for cnt in contours:
    perimeter = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.03 * perimeter, True)
    if (len(approx) == 4 and cv2.isContourConvex(approx) and maxAreaFound < cv2.contourArea(approx) < MAX_COUNTOUR_AREA):
        maxAreaFound = cv2.contourArea(approx)
        pageContour = approx

相关参考图像

  • 原图:原始图像
  • 阈值处理图:阈值图
  • 边缘检测图:边缘图

完整代码

import numpy as np
import cv2

def resize(img, height=800):
    """ Resize image to given height """
    rat = height / img.shape[0]
    return cv2.resize(img, (int(rat * img.shape[1]), height))

def fourCornersSort(pts):
    diff = np.diff(pts, axis=1)
    summ = pts.sum(axis=1)
    return np.array(
        [pts[np.argmin(summ)], pts[np.argmax(diff)], pts[np.argmax(summ)], pts[np.argmin(diff)]])

def contourOffset(cnt, offset):
    """ Offset contour, by 5px border """
    # Matrix addition
    cnt += offset
    # if value < 0 => replace it by 0
    cnt[cnt < 0] = 0
    return cnt

image = cv2.cvtColor(cv2.imread("9.jpg"), cv2.COLOR_BGR2RGB)
img = cv2.cvtColor(resize(image), cv2.COLOR_BGR2GRAY)
img = cv2.bilateralFilter(img, 9, 75, 75)
img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 4)
img = cv2.medianBlur(img, 11)
img = cv2.copyMakeBorder(img, 5, 5, 5, 5, cv2.BORDER_CONSTANT, value=[0, 0, 0])
edges = cv2.Canny(img, 200, 250)
im2, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

height = edges.shape[0]
width = edges.shape[1]
MAX_COUNTOUR_AREA = (width - 10) * (height - 10)
maxAreaFound = MAX_COUNTOUR_AREA * 0.5
pageContour = np.array([[5, 5], [5, height-5], [width-5, height-5], [width-5, 5]])

for cnt in contours:
    perimeter = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.03 * perimeter, True)
    if (len(approx) == 4 and cv2.isContourConvex(approx) and maxAreaFound < cv2.contourArea(approx) < MAX_COUNTOUR_AREA):
        maxAreaFound = cv2.contourArea(approx)
        pageContour = approx

pageContour = fourCornersSort(pageContour[:, 0])
pageContour = contourOffset(pageContour, (-5, -5))

sPoints = pageContour.dot(image.shape[0] / 800)
height = max(np.linalg.norm(sPoints[0] - sPoints[1]), np.linalg.norm(sPoints[2] - sPoints[3]))
width = max(np.linalg.norm(sPoints[1] - sPoints[2]), np.linalg.norm(sPoints[3] - sPoints[0]))

tPoints = np.array([[0, 0], [0, height], [width, height], [width, 0]], np.float32)
if sPoints.dtype != np.float32:
    sPoints = sPoints.astype(np.float32)

M = cv2.getPerspectiveTransform(sPoints, tPoints)
newImage = cv2.warpPerspective(image, M, (int(width), int(height)))
cv2.imwrite("resultImage.jpg", cv2.cvtColor(newImage, cv2.COLOR_BGR2RGB))

错误原因分析

我帮你排查了下,这个AxisError的核心问题出在轮廓数据的维度不匹配上:

  1. 正常情况下,cv2.findContours返回的轮廓cnt是(N,1,2)形状的3维数组,经过cv2.approxPolyDP处理后得到的4边形approx也应该是(4,1,2)的3维数组。但在这张特定图像里,可能存在一些细碎的异常小轮廓,这些轮廓的点集是1维数组,导致近似多边形后得到的approx也变成了1维。

  2. 当你用len(approx) ==4判断时,1维数组的长度确实可能是4,但后续把这个1维的approx赋值给pageContour后,执行pageContour[:, 0]就会直接报错——因为1维数组根本没有axis=1这个维度。

  3. 另外还有一种小概率情况:如果循环里完全没找到符合条件的4边形轮廓,pageContour还是你初始定义的2维数组,这时候pageContour[:,0]是没问题的,但显然你的情况是找到了异常的4点轮廓。

解决办法

你只需要在循环里增加对approx维度的检查,确保它是符合预期的3维数组,再进行后续判断就行:

修改循环部分的代码:

for cnt in contours:
    perimeter = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.03 * perimeter, True)
    # 先检查维度,确保是3维的轮廓数据,再判断其他条件
    if approx.ndim == 3 and len(approx) == 4 and cv2.isContourConvex(approx):
        area = cv2.contourArea(approx)
        if maxAreaFound < area < MAX_COUNTOUR_AREA:
            maxAreaFound = area
            pageContour = approx

保险起见,你还可以在处理pageContour前再做一次维度校验,防止意外情况:

# 确保pageContour是3维,转换为(4,2)的点集用于排序
if pageContour.ndim == 3:
    pageContour = fourCornersSort(pageContour[:, 0])
else:
    # 如果是异常情况,直接用初始定义的矩形轮廓(或者根据你的需求做其他处理)
    pageContour = fourCornersSort(pageContour)

这样就能彻底避免因为异常轮廓的维度问题触发AxisError了。

内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 08:57:42