找不到 OpenCV python canny 必需的参数“threshold2”(位置 4)

Geo*_*rey 5 python opencv numpy

我试图在将文本发送到 tesseract4 引擎以最大化结果之前,使用 openCV 从图像中分离文本。

我发现了这个有趣的帖子,我决定复制源代码并通过 mysdelf 尝试

但是我在第一次调用 OpenCV时遇到了问题

重现:

  1. 只需从要点中复制代码

  2. 启动命令 script.py /path/to/image.jpg

我遇到问题: Required argument 'threshold2' (pos 4) not found

你可能知道这意味着什么。我是一名 javascript、java 和 bash 脚本开发人员,但不是 python ......

在一个简单的版本中:

import glob
import os
import random
import sys
import random
import math
import json
from collections import defaultdict

import cv2
from PIL import Image, ImageDraw
import numpy as np
from scipy.ndimage.filters import rank_filter

if __name__ == '__main__':
    if len(sys.argv) == 2 and '*' in sys.argv[1]:
        files = glob.glob(sys.argv[1])
        random.shuffle(files)
    else:
        files = sys.argv[1:]

    for path in files:
        out_path = path.replace('.jpg', '.crop.png')
        if os.path.exists(out_path): continue
        orig_im = Image.open(path)
        edges = cv2.Canny(np.asarray(orig_im), 100, 200)
Run Code Online (Sandbox Code Playgroud)

在此先感谢您的帮助

alk*_*asm 4

编辑:好吧,这个答案显然是错误的,因为我尝试将自己的 16 位 int 图像发送到函数中,但无法重现结果。

\n\n

Edit2:所以我可以用以下命令重现错误:

\n\n
from PIL import Image\nimport numpy as np\nimport cv2\n\norig_im = Image.open(\'opencv-logo2.png\')\n\nthreshold1 = 50\nthreshold2 = 150\nedges = cv2.Canny(orig_im, 50, 100)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

类型错误:未找到所需参数“threshold2”(位置 4)

\n
\n\n

因此,如果图像没有转换为数组,即Image传入了类,我会收到错误。PILImage类是一个除了与其关联的图像数据之外还有很多东西的类,因此np.array必须强制转换为 a 才能传递到函数中。但如果选角得当,一切对我来说都很顺利。

\n\n

在与Dan Ma\xc5\xa1ek的聊天中,我的以下想法有点不正确。确实,较新的Canny()方法需要 16 位图像,但绑定不会查看实际的 numpydtype来查看它的位深度来决定使用哪个函数调用。另外,如果您尝试实际发送uint16图像,则会收到不同的错误:

\n\n
edges = cv2.Canny(np.array([[0, 1234], [1234, 2345]], dtype=np.uint16), 50, 100)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

错误:(-215) 函数 Canny 中的深度 == CV_8U

\n
\n\n

所以我最初给出的答案(如下)并不是罪魁祸首。也许你不小心删除了np.array()的转换orig_im并得到了该错误,或​​者,发生了其他奇怪的事情。

\n\n
\n\n

原始(错误)答案

\n\n

在OpenCV 3.2.0中,引入了一种新方法,Canny()允许用户指定自己的梯度图像。在最初的实现中,Canny()将使用Sobel()运算符来计算梯度,但现在您可以计算导Scharr()数并将传递给Canny()。所以这很酷。但这和你的问题有什么关系呢?

\n\n

Canny()方法已重载。它根据您发送的参数决定您要使用哪个函数。最初的调用Canny()使用所需参数的原始调用如下所示

\n\n
cv2.Canny(image, threshold1, threshold2)\n
Run Code Online (Sandbox Code Playgroud)\n\n

但新的重载方法看起来像

\n\n
cv2.Canny(grad_x, grad_y, threshold1, threshold2)\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,您的错误消息中有一条提示:

\n\n
\n

未找到所需参数“threshold2”(位置 4)

\n
\n\n

这些调用中哪一个位于threshold2位置 4?较新的方法调用!那么,如果您只传递了三个参数,为什么会调用它呢?请注意,如果您使用图像,则会收到错误PIL,但如果您使用numpy图像,则不会收到错误。那么还有什么让它假设您正在使用新的呼叫呢?

\n\n

如果您检查OpenCV 3.3.0Canny()文档,您将看到原始Canny()调用需要第一个位置参数的8 位输入图像Canny(),而新调用需要输入图像的 16 位 x 导数(CV_16SC1 或 CV_16SC3 )对于第一个位置参数。

\n\n

将两个和两个放在一起,PIL 为您提供了一个 16 位输入图像,因此 OpenCV 认为您正在尝试调用新方法。

\n\n

因此,如果您想继续使用 PIL,这里的解决方案是将图像转换为 8 位表示。Canny()首先需要单通道(即灰度)图像来运行。因此,您需要image首先确保它是单通道,然后缩放它并更改 numpy dtype。我相信 PIL 会将灰度图像读取为单通道(OpenCV 默认情况下将所有图像读取为三通道,除非您另有说明)。

\n\n

如果图像是 16 位,则使用 numpy 转换很容易:

\n\n
img = (img/256).astype(\'uint8\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

这假设img是一个 numpy 数组,因此您需要将 PIL 图像转换为ndarray首先使用np.array()np.asarray()

\n\n

然后您应该能够Canny()使用原始函数调用运行。

\n