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

安装numpy、easyocr后cv2报gapi_wip_gst_GStreamerPipeline属性错误解决

问题背景

在Python 3.10环境下开发票据OCR识别功能,此前相关代码运行完全正常,执行numpy、easyocr库安装操作后突发运行异常,全程未修改业务代码逻辑。曾尝试降级OpenCV版本,但操作后触发其他新异常,测试过多数线上公开的同类问题解决方案,均未解决问题。

报错信息

运行代码时抛出AttributeError,报错定位到C:\Users\user\AppData\Roaming\Python\Python310\site-packages\cv2\gapi\__init__.py文件第290行,执行cv.gapi.wip.GStreamerPipeline = cv.gapi_wip_gst_GStreamerPipeline语句时触发异常,提示:

partially initialized module 'cv2' has no attribute 'gapi_wip_gst_GStreamerPipeline' (most likely due to a circular import)

即部分初始化的cv2模块无gapi_wip_gst_GStreamerPipeline属性,大概率由循环导入导致。

业务代码

代码主要实现票据图片的轮廓提取、透视矫正、灰度处理,最终调用easyocr完成文字识别提取,完整代码如下:

import cv2
import numpy as np
import easyocr
from nltk.corpus import words
from nltk.metrics.distance import jaccard_distance
from nltk.util import ngrams
# this needs to run only once to load the model into memory
file_name = 'Image/Image/7.jpg'

image = cv2.imread(file_name)


def opencv_resize(image, ratio):
    width = int(image.shape[1] * ratio)
    height = int(image.shape[0] * ratio)
    dim = (width, height)
    # return cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
    return cv2.resize(image, dim, interpolation=cv2.INTER_NEAREST)


# def plot_rgb(image=image):
#     return cv2.imshow('rgb', cv2.cvtColor(image, cv2.COLOR_BGR2RGB))


# def plot_gray(image=image):
#     return cv2.imshow('gray', image)


# Downscale image as finding receipt contour is more efficient on a small image
resize_ratio = 500 / image.shape[0]


original = image.copy()
image = opencv_resize(image, resize_ratio)
# cv2.imshow('downscaled', image)
# Convert to grayscale for further processing
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# plot_gray(gray)
ret, img = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY, cv2.THRESH_OTSU)


# Detect all contours in Canny-edged image
contours, hierarchy = cv2.findContours(
    img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
image_with_contours = cv2.drawContours(
    image.copy(), contours, -1, (0, 255, 0), 3)
# plot_rgb(image_with_contours)


# Get 10 largest contours
largest_contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
image_with_largest_contours = cv2.drawContours(
    image.copy(), largest_contours, -1, (0, 255, 0), 3)
# plot_rgb(image_with_largest_contours)
# approximate the contour by a more primitive polygon shape


def approximate_contour(contour):
    peri = cv2.arcLength(contour, True)
    return cv2.approxPolyDP(contour, 0.032 * peri, True)


def get_receipt_contour(contours):
    # loop over the contours
    for c in contours:
        approx = approximate_contour(c)

        # if our approximated contour has four points, we can assume it is receipt's rectangle
        # if len(approx) == 4:
        if len(approx) == 4:
            return approx


get_receipt_contour(largest_contours)

receipt_contour = get_receipt_contour(largest_contours)
image_with_receipt_contour = cv2.drawContours(
    image.copy(), [receipt_contour], -1, (0, 255, 0), 2)


def contour_to_rect(contour):
    pts = contour.reshape(4, 2)
    rect = np.zeros((4, 2), dtype="float32")
    # top-left point has the smallest sum
    # bottom-right has the largest sum
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    return rect / resize_ratio


def wrap_perspective(img, rect):
    # unpack rectangle points: top left, top right, bottom right, bottom left
    (tl, tr, br, bl) = rect
    # compute the width of the new image
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    # compute the height of the new image
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    # take the maximum of the width and height values to reach
    # our final dimensions
    maxWidth = max(int(widthA), int(widthB))
    maxHeight = max(int(heightA), int(heightB))
    # destination points which will be used to map the screen to a "scanned" view
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")
    M = cv2.getPerspectiveTransform(rect, dst)
    return cv2.warpPerspective(img, M, (maxWidth, maxHeight))


scanned = wrap_perspective(original.copy(), contour_to_rect(receipt_contour))


def bw_scanner(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    return gray


result = bw_scanner(scanned)



correct_words = words.words()


def wordDetectionAndExtraction(img):
    reader = easyocr.Reader(['en'])
    readImage = reader.readtext(img, detail=0)
    return readImage

print(wordDetectionAndExtraction(result))
问题原因

报错本质是OpenCV版本与easyocr依赖版本不兼容,加上用户目录下残留多版本OpenCV文件,导致cv2模块加载时出现循环引用,无法正常初始化gapi相关属性。之前盲目降级OpenCV时没有清理干净残留文件,出现版本错配,所以触发其他异常。

解决步骤
  • 彻底卸载所有OpenCV相关包,执行以下命令:
    pip uninstall -y opencv-python opencv-contrib-python opencv-python-headless
    如果之前用conda安装过OpenCV,额外执行conda remove -y opencv。卸载完成后手动删除C:\Users\user\AppData\Roaming\Python\Python310\site-packages路径下所有名称以cv2开头的文件夹,避免旧版本残留文件干扰。
  • 安装经过兼容性验证的固定版本依赖,不要使用最新版OpenCV和1.24以上版本numpy:
    pip install numpy==1.23.5 opencv-python==4.5.5.62 opencv-contrib-python==4.5.5.62 easyocr==1.7.0
  • 调整代码结构,把全局作用域下直接执行的图片读取、处理逻辑放到if __name__ == "__main__":代码块中,避免模块导入阶段就触发cv2加载,进一步规避循环导入风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:45:31