如何在 Python 中停止打印 OpenCV 错误消息

2024-02-17

Same as 这个问题在这里 https://stackoverflow.com/questions/17567808/how-to-suppress-opencv-error-message/17575610#17575610,除了 Python,而不是 C++。

我在 OpenCV 中有一条错误消息,即使我在它周围做了一个 except catch ,它也会打印出来。

The 链接问题的解决方案 https://stackoverflow.com/a/17575610/5049813建议使用重定向功能,但是这条评论 https://stackoverflow.com/questions/43919314/do-not-display-python-opencv-error#comment74879338_43919314表明 OpenCV 的 Python 中不存在该函数。

如何停止打印 OpenCV 错误消息,同时仍允许我准确打印我想要的内容?


在撰写此答案时(OpenCV 3.4.1 是最后发布的版本),没有办法只过滤默认错误处理程序(我能想到的)的输出,也没有办法更改错误处理程序。

然而,你的问题让我思考——在highgui模块中,我们已经有几个函数可以让我们为鼠标、轨迹栏和按钮事件设置 Python 回调,因此我们可以从该代码中获取灵感并修补这个新功能。

让我们使用 3.4.1 版本。感兴趣的文件是modules/python/src2/cv2.cpp https://github.com/opencv/opencv/blob/3.4.1/modules/python/src2/cv2.cpp。我们将从函数中获取灵感开始OnMouse https://github.com/opencv/opencv/blob/3.4.1/modules/python/src2/cv2.cpp#L1538 and pycvSetMouseCallback https://github.com/opencv/opencv/blob/3.4.1/modules/python/src2/cv2.cpp#L1556.

让我们让 Python 错误处理程序有一个与C++ 错误处理程序 https://github.com/opencv/opencv/blob/3.4.1/modules/core/include/opencv2/core/utility.hpp#L168:

error_handler([int]status, [str]func_name, [str]err_msg, [str]file_name, [int]line, [obj]userdata) -> None

让我们还添加对重置为默认错误处理程序的支持——一些highgui功能还没有做到。

首先,我们需要一个静态错误处理函数,它将参数从 C++ 编组到 Python,并调用适当的 Python 函数来处理错误。就像我们从中获得灵感的函数一样,我们将使用用户数据参数来保存一个由函数对象和可选的 Python 用户数据组成的元组。

static int OnError(int status, const char *func_name, const char *err_msg, const char *file_name, int line, void *userdata)
{
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();

    PyObject *o = (PyObject*)userdata;
    PyObject *args = Py_BuildValue("isssiO", status, func_name, err_msg, file_name, line, PyTuple_GetItem(o, 1));

    PyObject *r = PyObject_Call(PyTuple_GetItem(o, 0), args, NULL);
    if (r == NULL) {
        PyErr_Print();
    } else {
        Py_DECREF(r);
    }

    Py_DECREF(args);
    PyGILState_Release(gstate);

    return 0; // The return value isn't used
}

接下来,我们需要编写函数来实现Python和C++之间的绑定。然而,由于我的怀疑潜在的内存泄漏 https://github.com/opencv/opencv/issues/11206在我们从中汲取灵感的函数中,我们将进行一些补充来解决这个问题——我们将跟踪最新的用户数据对象并根据需要取消引用它。

// Keep track of the previous handler parameter, so we can decref it when no longer used
static PyObject* last_on_error_param = NULL;

static PyObject *pycvRedirectError(PyObject*, PyObject *args, PyObject *kw)
{
    const char *keywords[] = { "on_error", "param", NULL };
    PyObject *on_error;
    PyObject *param = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kw, "O|O", (char**)keywords, &on_error, &param))
        return NULL;

    if ((on_error != Py_None) && !PyCallable_Check(on_error))  {
        PyErr_SetString(PyExc_TypeError, "on_error must be callable");
        return NULL;
    }
    if (param == NULL) {
        param = Py_None;
    }

    if (last_on_error_param) {
        Py_DECREF(last_on_error_param);
        last_on_error_param = NULL;
    }

    if (on_error == Py_None) {
        ERRWRAP2(redirectError(NULL));        
    } else {
        last_on_error_param = Py_BuildValue("OO", on_error, param);
        ERRWRAP2(redirectError(OnError, last_on_error_param));
    }
    Py_RETURN_NONE;
}

最后,我们必须注册我们的“特殊方法” https://github.com/opencv/opencv/blob/3.4.1/modules/python/src2/cv2.cpp#L1684。与我们从中获得灵感的函数不同,我们不依赖于某些 GUI,并且我们希望它始终可用,因此我们将代码修改为如下所示:

static PyMethodDef special_methods[] = {
  {"redirectError", (PyCFunction)pycvRedirectError, METH_VARARGS | METH_KEYWORDS, "redirectError(onError [, param]) -> None"},
#ifdef HAVE_OPENCV_HIGHGUI
  {"createTrackbar", pycvCreateTrackbar, METH_VARARGS, "createTrackbar(trackbarName, windowName, value, count, onChange) -> None"},
  {"createButton", (PyCFunction)pycvCreateButton, METH_VARARGS | METH_KEYWORDS, "createButton(buttonName, onChange [, userData, buttonType, initialButtonState]) -> None"},
  {"setMouseCallback", (PyCFunction)pycvSetMouseCallback, METH_VARARGS | METH_KEYWORDS, "setMouseCallback(windowName, onMouse [, param]) -> None"},
#endif
  {NULL, NULL},
};

现在我们可以重建 OpenCV、安装并测试它。我编写了以下脚本来演示功能:

import cv2

def verbose_error_handler(status, func_name, err_msg, file_name, line, userdata):
    print "Status = %d" % status
    print "Function = %s" % func_name
    print "Message = %s" % err_msg
    print "Location = %s(%d)" % (file_name, line)
    print "User data = %r" % userdata

def silent_error_handler(status, func_name, err_msg, file_name, line, userdata):
    pass


print "** Default handler"
try:
    cv2.imshow("", None) # This causes an assert
except cv2.error as e:
    pass

print "** Using verbose handler"
cv2.redirectError(verbose_error_handler, 42)
try:
    cv2.imshow("", None) # This causes an assert
except cv2.error as e:
    pass

print "** Using silent handler"
cv2.redirectError(silent_error_handler)
try:
    cv2.imshow("", None) # This causes an assert
except cv2.error as e:
    pass

print "** Back to default handler"
cv2.redirectError(None)
try:
    cv2.imshow("", None) # This causes an assert
except cv2.error as e:
    pass

使用我的 OpenCV 修补版本(基于上述说明),我在控制台上得到以下输出:

** Default handler
OpenCV(3.4.1) Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file F:\GitHub\opencv\modules\highgui\src\window.cpp, line 364
** Using verbose handler
Status = -215
Function = cv::imshow
Message = size.width>0 && size.height>0
Location = F:\GitHub\opencv\modules\highgui\src\window.cpp(364)
User data = 42
** Using silent handler
** Back to default handler
OpenCV(3.4.1) Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file F:\GitHub\opencv\modules\highgui\src\window.cpp, line 364

当我开始写这个答案时,我的想法之一是,自从默认错误处理程序 https://github.com/opencv/opencv/blob/fed22f2f5c17f28b07e56694825beb94f6574bcc/modules/core/src/system.cpp#L888使用以下格式化字符串将所有这些消息输出到stderr

"OpenCV(%s) Error: %s (%s) in %s, file %s, line %d"

我们也许可以钩住stderr流,并过滤掉以常量前缀开头的任何行。唉,我没能实现这一目标。也许其他人可以?


编辑:修补合并到opencv:master经过一些小的修改(主要是我们去掉了用户数据参数,因为它在 Python 中是不必要的)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Python 中停止打印 OpenCV 错误消息 的相关文章

随机推荐

  • 如何将多部分表单数据从jsp发送到Web服务?

    我正在尝试为我的网站创建一个注册页面 当用户将数据提交到signup jsp时 我想使用 application x www form urlencoded 将此数据发送到我的Web服务 我怎样才能在JSP中做到这一点 尝试了以下代码 但这
  • 如何将字符串从函数传递到主函数?

    我尝试寻找解决方案 但未能找到 是否可以返回字符串 我想将一个字符串从下面的函数传递回 main 我想通过listofdeatils string 这是我的代码 include
  • 如何使用 Fetch 发布 x-www-form-urlencoded 请求?

    我有一些参数想要以表单编码的方式 POST 到我的服务器 userName email protected cdn cgi l email protection password Password grant type password 我
  • 如何链接winsock.lib?

    在我的 C 课程中 我使用套接字 我在链接时遇到一些错误 因为在我看来 库 Winsock lib 丢失了 我包括这些 ifdef WIN32 include
  • Pro JavaScript 程序员面试问题(含答案)[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 重定向到登录页面时正确的 HTTP 状态代码是什么?

    当用户未登录并尝试访问需要登录的页面时 重定向到登录页面的正确 HTTP 状态代码是什么 我问是因为没有一个W3C 规定的 3xx 响应代码 http www w3 org Protocols rfc2616 rfc2616 sec10 h
  • 插入表..在链接服务器上执行不起作用

    这有效 返回结果集 exec select col count 1 from test dbo Table1 with nolock at svrA 当我尝试将结果集插入表中时 insert into rowcount sub tablen
  • 如何在 IIS 7 中配置 Http 处理程序?

    这就是我想做的 我创建了一个类库项目 这有一个类实现 IHttpHandler 接口 让我们 将该类命名为 ZipHandler 让我们 假设命名空间是 Zip 我希望每当任何 Http 请求提供 zip 文件 我的 ZipHandler
  • PHP 有类似 ruby​​ gem 的打包器吗?

    我是 PHP 程序员 了解 Rails Ruby 宝石捆绑器 http gembundler com 非常好的安装依赖项的工具 php有类似的东西吗 也许某些php框架有这样的工具 关于gem捆绑器的说明 Bundler 在应用程序的整个生
  • MalformedInputException 与 Files.readAllLines()

    我正在迭代一些文件 准确地说是 5328 个文件 这些文件是平均 XML 文件 最多 60 200 行 它们首先通过简单的方法进行过滤isXml源文件解析路径 Files walk Paths get home me development
  • 如何使用 codeigniter 查询获取每个产品的平均评分?

    我有评级表 其中对用户给出的每个产品进行评级 我正在检索所有评级记录 但同时我想根据每个产品获得平均评级 但我无法获得输出 Query this gt db gt select ratings this gt db gt select se
  • Python:名称解析;函数 def 的顺序

    我有一个非常简单的例子 usr bin env python a 1 NameError name a is not defined b 1 NameError name b is not defined c 1 NameError nam
  • Segue 未获取选定的行号

    我正在将数据从表视图控制器传递到详细视图 我尝试使用indexPath row直接在我的prepareForSegue方法 但是它显示错误 使用未解析的标识符 indexPath 因此 在搜索网络后 我设置了变量indexOfSelecte
  • 如何在 Android 版 Eclipse 中启用 LogCat/Console?

    在 Android 中编写一个简单的程序时 我错误地关闭了 LogCat 窗口 我想知道如何再次显示它 在 Eclipse 中 转到 窗口 gt 显示视图 gt 其他 gt Android gt Logcat Logcat 只是模拟器或设备
  • Excel VBA 在表格下方添加数据时扩展表格

    我在 Excel 中有一个表格 当用户在表格后添加数据时 该数据不属于该表格 我创建了一个可以执行来扩展表的代码 代码如下 Sub ExtendTableToLastRow Sheets Update Select If ActiveShe
  • 如何使用 Woocommerce WC_AJAX 类

    我正在开发一个基于 Wordpress WooCommerce 的商店 我使用ajax来调用数据 但我是通过 wp admin admin ajax php 在 function php 文件中使用我自己的函数来完成此操作 昨天我在 woo
  • ruby:“p *1..10”中的星号是什么意思

    the line p 1 10 做完全相同的事情 1 10 each x puts x 这将为您提供以下输出 ruby e p 1 10 1 2 3 4 5 6 7 8 9 10 例如 在使用 textmate 时 这是一个很好的快捷方式
  • 如何在ListView中正确使用TextSwitcher?

    My TextSwitcher对于每条记录ListView应显示第一个值 text1 然后是另一个值 text2 然后再次首先值 依此类推 仅当以下情况时才会发生text2不是空的 否则text1应始终显示 没有任何更改和动画 我已经创建了
  • log4j2.xml中每个包的Log4J不同日志级别

    我有一个 Java Web 应用程序log4j2 xml我需要为每个包设置不同的级别 例如 com myexample firstmodule 这应该是INFO level com myexample secondmodule 这应该是TR
  • 如何在 Python 中停止打印 OpenCV 错误消息

    Same as 这个问题在这里 https stackoverflow com questions 17567808 how to suppress opencv error message 17575610 17575610 除了 Pyt