【问题标题】:How to stop OpenCV error message from printing in Python如何阻止 OpenCV 错误消息在 Python 中打印
【发布时间】:2018-09-11 03:36:19
【问题描述】:

this question here 相同,但 Python 除外,而不是 C++。

我在 OpenCV 中有一条错误消息正在打印,即使我在它周围执行了异常捕获。

solution to the linked question 建议使用重定向函数,但this comment 建议 Python 中不存在用于 OpenCV 的函数。

我怎样才能停止打印 OpenCV 错误消息,同时仍然允许我准确地打印我想要的内容?

【问题讨论】:

  • 投反对票,因为所有有问题的数据都是指其他链接,这里没有给出太多数据或说明
  • @Prateek 如果我遇到与其他人完全相同的问题,我该怎么办,只是使用另一种语言?我想我已经在这里包含了足够的细节供某人解决问题,而我的研究(通过另一个问题找到)在我的情况下不起作用。 (另外,谢谢你的解释!)
  • 请检查how to ask questionMinimal, Complete, and Verifiable example 您应该考虑在这里从另一个问题重写选择性内容(评论、解决方案等),用户不必查看其他问题的所有细节。希望对您有所帮助。
  • @Prateek 恕我直言,这是一个陈述良好的问题,表明正在进行研究工作,据我所知,它没有满足 OP 要求的解决方案(仅删除默认情况下的 OpenCV 错误消息)到stderr)。

标签: python opencv


【解决方案1】:

建议的答案对我不起作用 - 我从未见过回调调用。但是,您可以使用环境变量 as shown here 控制 OpenCV 日志记录。

我假设环境变量在启动时被读取一次,所以最好在导入之前设置它。

如果你希望所有消息都消失,你可以使用这个

os.environ["OPENCV_LOG_LEVEL"]="SILENT"
import cv2

或者只是为了抑制错误(和更低):

os.environ["OPENCV_LOG_LEVEL"]="FATAL"
import cv2

有关其他值,请参阅 OpenCV log level definitions

【讨论】:

    【解决方案2】:

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

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

    让我们使用 3.4.1 版本。感兴趣的文件是modules/python/src2/cv2.cpp。我们将从函数OnMousepycvSetMouseCallback 中获取灵感。

    让我们让 Python 错误处理程序具有与 C++ error handler 匹配的签名:

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

    让我们还添加对重置为默认错误处理程序的支持——highgui 函数还没有这样做。

    首先,我们需要一个静态错误处理函数,它将参数从 C++ 编组到 Python,并调用适当的 Python 函数来处理错误。就像我们从中获得灵感的函数一样,我们将使用 user data 参数来保存一个由函数对象和可选 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++ 之间的绑定。但是,由于我的 suspicions of potential memory leaks 在我们从中获得灵感的函数中,我们将做一些补充来解决这个问题——我们将跟踪最新的用户数据对象并在必要时取消引用它。

    // 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;
    }
    

    最后,我们必须注册我们的"special method"。与我们从中获得灵感的函数不同,我们不依赖于某些 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
    

    当我开始写这个答案时,我的一个想法是,由于default error handler 使用以下格式字符串将所有这些消息输出到stderr

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

    我们或许可以挂钩stderr 流,并过滤掉所有以常量前缀开头的行。唉,我无法做到这一点。也许其他人可以?


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

    【讨论】:

    • 我看看能不能把它推送到主要的 OpenCV 仓库,然后这将成为未来版本的标准功能。
    • 补丁的当前pull request
    猜你喜欢
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2015-06-14
    • 1970-01-01
    相关资源
    最近更新 更多