From 7dd14a26db3752e4cecbfce7984201a3ba228893 Mon Sep 17 00:00:00 2001 From: Guillaume Raffy Date: Tue, 10 May 2016 18:37:49 +0200 Subject: [PATCH] now, whenever an exception is raised in the graph cut c++ code, the message detailing the reason of the failure is displayed --- README.md | 3 +-- gco_exception_handler.cpp | 29 +++++++++++++++++++++++++ gco_exception_handler.hpp | 1 + gco_python.pyx | 45 ++++++++++++++++++++++++++------------- setup.py | 1 + 5 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 gco_exception_handler.cpp create mode 100644 gco_exception_handler.hpp diff --git a/README.md b/README.md index 6b12328..f6a0254 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,7 @@ Note that from a probabilistic viewpoint, GCO works in log-space. Note that all input arrays are assumed to be in int32. This means that float potentials must be rounded! -These algorithms can only deal with certain energies. Unfortunately -I have not figured out yet how to convert C++ errors to Python. If an unknown +These algorithms can only deal with certain energies. If an error is raised, it probably means that you used an invalid energy function. Look at the gco README for details. diff --git a/gco_exception_handler.cpp b/gco_exception_handler.cpp new file mode 100644 index 0000000..6197668 --- /dev/null +++ b/gco_exception_handler.cpp @@ -0,0 +1,29 @@ +#include "Python.h" +#include "GCoptimization.h" +#include +#include + +using namespace std; + +extern PyObject *gcerror; // a python exception object that represents the graph cut exception in python + +/** + \brief this function translates graph cut exceptions into python exceptions. + + It uses the mechanism described in http://stackoverflow.com/questions/10684983/handling-custom-c-exceptions-in-cython +*/ +void handle_gco_exception() +{ + try + { + throw; + } + catch (GCException& e) + { + PyErr_SetString(gcerror, e.message); + } + catch (const std::exception& e) + { + PyErr_SetString(PyExc_RuntimeError, e.what() ); + } +} diff --git a/gco_exception_handler.hpp b/gco_exception_handler.hpp new file mode 100644 index 0000000..4e885f1 --- /dev/null +++ b/gco_exception_handler.hpp @@ -0,0 +1 @@ +void handle_gco_exception(); diff --git a/gco_python.pyx b/gco_python.pyx index bc82b6b..c121ad1 100644 --- a/gco_python.pyx +++ b/gco_python.pyx @@ -1,27 +1,42 @@ import numpy as np cimport numpy as np + np.import_array() +# we use the mechanism described in http://stackoverflow.com/questions/10684983/handling-custom-c-exceptions-in-cython to translate graph-cut c++ exceptions into python exceptions that will allow the user to see the message detailing the graph cut exception. +from python_object cimport PyObject +class GCError(RuntimeError): + """ + This class represents a graph cut error (exception) + """ + pass + +# make the GCError class accessible to c++, so that the c++ function handle_gco_exception can use it +cdef public PyObject* gcerror = GCError + +cdef extern from "gco_exception_handler.hpp": + cdef void handle_gco_exception() + cdef extern from "GCoptimization.h": cdef cppclass GCoptimizationGridGraph: - GCoptimizationGridGraph(int width, int height, int n_labels) except + - void setDataCost(int *) except + - void setSmoothCost(int *) except + - void expansion(int n_iterations) except + - void swap(int n_iterations) except + - void setSmoothCostVH(int* pairwise, int* V, int* H) except + - int whatLabel(int node) except + + GCoptimizationGridGraph(int width, int height, int n_labels) except +handle_gco_exception + void setDataCost(int *) except +handle_gco_exception + void setSmoothCost(int *) except +handle_gco_exception + void expansion(int n_iterations) except +handle_gco_exception + void swap(int n_iterations) except +handle_gco_exception + void setSmoothCostVH(int* pairwise, int* V, int* H) except +handle_gco_exception + int whatLabel(int node) except +handle_gco_exception cdef cppclass GCoptimizationGeneralGraph: - GCoptimizationGeneralGraph(int n_vertices, int n_labels) except + - void setDataCost(int *) except + - void setSmoothCost(int *) except + - void setNeighbors(int, int) except + - void setNeighbors(int, int, int) except + - void expansion(int n_iterations) except + - void swap(int n_iterations) except + - int whatLabel(int node) except + + GCoptimizationGeneralGraph(int n_vertices, int n_labels) except +handle_gco_exception + void setDataCost(int *) except +handle_gco_exception + void setSmoothCost(int *) except +handle_gco_exception + void setNeighbors(int, int) except +handle_gco_exception + void setNeighbors(int, int, int) except +handle_gco_exception + void expansion(int n_iterations) except +handle_gco_exception + void swap(int n_iterations) except +handle_gco_exception + int whatLabel(int node) except +handle_gco_exception def cut_simple(np.ndarray[np.int32_t, ndim=3, mode='c'] unary_cost, diff --git a/setup.py b/setup.py index 129eb20..5e21932 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ 'maxflow.cpp'] files = [os.path.join(gco_directory, f) for f in files] +files.insert(0, "gco_exception_handler.cpp") files.insert(0, "gco_python.pyx") setup(cmdclass={'build_ext': build_ext},