在撰写此答案(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 usedstatic 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, ¶m)) 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 cv2def 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" % userdatadef silent_error_handler(status, func_name, err_msg, file_name, line, userdata): passprint "** Default handler"try: cv2.imshow("", None) # This causes an assertexcept cv2.error as e: passprint "** Using verbose handler"cv2.redirectError(verbose_error_handler, 42)try: cv2.imshow("", None) # This causes an assertexcept cv2.error as e: passprint "** Using silent handler"cv2.redirectError(silent_error_handler)try: cv2.imshow("", None) # This causes an assertexcept cv2.error as e: passprint "** Back to default handler"cv2.redirectError(None)try: cv2.imshow("", None) # This causes an assertexcept cv2.error as e: pass使用修补程序的OpenCV版本(基于上述说明),我在控制台上获得以下输出:
** Default handlerOpenCV(3.4.1) Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file F:GitHubopencvmoduleshighguisrcwindow.cpp, line 364** Using verbose handlerStatus = -215Function = cv::imshowMessage = size.width>0 && size.height>0Location = F:GitHubopencvmoduleshighguisrcwindow.cpp(364)User data = 42** Using silent handler** Back to default handlerOpenCV(3.4.1) Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file F:GitHubopencvmoduleshighguisrcwindow.cpp, line 364
就在我开始编写此答案时,我的想法之一是,由于默认错误处理程序使用以下格式的字符串将所有这些消息输出到
stderr
"OpenCV(%s) Error: %s (%s) in %s, file %s, line %d"
我们也许可以钩住
stderr流,并过滤掉以常量前缀开头的所有行。,我无法实现这一目标。也许别人可以吗?
编辑:修补程序合并
opencv:master了一些小的修改(主要是我们摆脱了用户数据参数,因为它在Python中是不必要的)。



