当前位置: 首页 > 面试题库 >

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

司寇昱
2023-03-14
问题内容

我在OpenCV中有一条错误消息正在打印,即使我在它周围进行了除外捕获也是如此。

链接问题的解决方案建议使用重定向功能,但是此注释表明该功能在Python forOpenCV中不存在。

如何停止打印OpenCV错误消息,同时仍然允许我完全打印所需的内容?


问题答案:

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

但是,您的问题让我开始思考-在 highgui
模块中,我们已经有了一些函数,可以让我们为鼠标,轨迹栏和按钮事件设置Python回调,因此我们可以从该代码中 汲取 灵感并将其添加为新功能。

让我们使用版本3.4.1。感兴趣的文件modules/python/src2/cv2.cpp。我们将从功能OnMouse和的灵感中开始pycvSetMouseCallback

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

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

让我们还添加支持以重置为默认错误处理程序-这些highgui功能尚无法实现。

首先,我们需要一个静态错误处理程序函数,该函数将把C
++中的参数编组为Python,并调用适当的Python函数来处理错误。就像我们从中汲取灵感的函数一样,我们将使用userdata参数来保存由函数对象和可选的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
++之间的绑定。但是,由于我怀疑我们正在汲取灵感的功能中可能存在内存泄漏,因此我们将进行一些补充以解决此问题-
我们将跟踪最新的用户数据对象,并在必要时取消引用。

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

最后,我们必须注册我们的“特殊方法”。与我们从中获得灵感的功能不同,我们不依赖某些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

就在我开始编写此答案时,我的想法之一是,由于默认错误处理程序使用以下格式的字符串将所有这些消息输出到stderr

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

我们也许可以钩住stderr流,并过滤掉以常量前缀开头的所有行。,我无法实现这一目标。也许别人可以吗?

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



 类似资料:
  • 问题内容: 我正在编写一个程序,该程序可以解析10个网站,找到数据文件,保存文件,然后解析它们以生成可以在NumPy库中轻松使用的数据。有万吨通过不良链接,不好的XML,缺项,其他的事情我还没有进行分类文件遇到错误的。我最初制作该程序来处理如下错误: 但是现在我想记录错误: 请注意,这是打印到日志文件中以供以后查看。这通常会打印出非常无用的数据。我想要的是在错误触发时打印完全相同的行,而没有try

  • 当发送、和时,我希望使用者处理并永远重试。在成功使用之前不应处理。实际发生的情况是,在两次重试之间被消耗。如何改变这种行为?有什么想法吗?

  • 问题内容: 我使用的是python库,该库导入了在stdout上打印的C共享库。我想要一个干净的输出以便与管道一起使用或在文件中重定向。打印是在python之外的共享库中完成的。 一开始,我的方法是: 第一种方法是行之有效的: -出于某种原因,它在移动标准输出之前需要一个“打印”语句,否则总是打印问候词。结果,它将打印一个空行,而不是库通常输出的所有模糊测试。 -更烦人的是,重定向到文件时失败:

  • 问题内容: 我知道python中的\ xb函数,但是它似乎对我不起作用。我知道我可能需要下载第三方模块来完成此任务,如果是这样,哪一个最好? 我目前正在编写一个二项式展开求解器,以尝试和使用我自学的技能。当我尝试显示用户输入的扩展用于确认时,就会出现问题。目前,我必须像这样打印表达式: 这将打印(2x4)^ 5,而我希望将索引打印为上标。如何才能做到这一点? 问题答案: 您可以使用为您执行必要格式

  • 问题内容: 我想打印一些日志以进行调试和测试,但是现有日志量很大,因此我想将自己的日志打印到stderr: 这样我就可以看到自己的日志。 我怎样才能做到这一点? 问题答案: 默认情况下,程序包将打印为。 您也可以直接使用(是)。

  • 问题内容: 我想为我的终端应用程序制作一个进度条,该进度条的工作原理如下: 这样可以直观地表明在该过程完成之前还剩下多少时间。 我知道我可以通过将它们添加到字符串中,然后简单地使用printf,来执行诸如打印越来越多的X的操作,但这看起来像: 或类似的东西(显然您可以按一定的间距来玩。)但是,这在视觉上并不美观。有没有一种方法可以用新文本更新终端中的打印文本而无需重新打印?这一切都在linux,c