HSImage
Hyperspectral Image Interface Library for ENVI-BIL image files
All Classes Functions Variables Typedefs Groups Pages
python_utils.h
1 #ifndef PYTHON_UTILS_H
2 #define PYTHON_UTILS_H
3 
4 #include <iostream>
5 #include <vector>
6 #include <opencv2/core.hpp>
7 
8 #include <boost/python.hpp>
9 #include <boost/python/stl_iterator.hpp>
10 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
11 
12 
15 struct iterable_converter
16 {
19  template <typename Container>
20  iterable_converter&
21  from_python()
22  {
23  boost::python::converter::registry::push_back(
24  &iterable_converter::convertible,
25  &iterable_converter::construct_from_python<Container>,
26  boost::python::type_id<Container>());
27 
28  // Support chaining.
29  return *this;
30  }
31 
32  template<class T>
33  boost::python::list to_python(std::vector<T> v)
34  {
35  typename std::vector<T>::iterator iter;
36  boost::python::list list;
37  for(iter = v.begin();iter != v.end(); ++iter)
38  {
39  list.append(*iter);
40  }
41  return list;
42  }
43 
45  static void* convertible(PyObject* object)
46  {
47  return PyObject_GetIter(object) ? object : NULL;
48  }
49 
57  template <typename Container>
58  static void construct_from_python(
59  PyObject* object,
60  boost::python::converter::rvalue_from_python_stage1_data* data)
61  {
62  namespace python = boost::python;
63  // Object is a borrowed reference, so create a handle indicting it is
64  // borrowed for proper reference counting.
65  python::handle<> handle(python::borrowed(object));
66 
67  // Obtain a handle to the memory block that the converter has allocated
68  // for the C++ type.
69  typedef python::converter::rvalue_from_python_storage<Container>
70  storage_type;
71  void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
72 
73  typedef python::stl_input_iterator<typename Container::value_type>
74  iterator;
75 
76  // Allocate the C++ type into the converter's memory block, and assign
77  // its handle to the converter's convertible variable. The C++
78  // container is populated by passing the begin and end iterators of
79  // the python object to the container's constructor.
80  new (storage) Container(
81  iterator(python::object(handle)), // begin
82  iterator()); // end
83  data->convertible = storage;
84  }
85 
86 };
87 
88 // Converts a std::pair instance to a Python tuple.
89 template <typename T1, typename T2>
90 struct std_pair_to_tuple
91 {
92  static PyObject* convert(std::pair<T1, T2> const& p)
93  {
94  return boost::python::incref(
95  boost::python::make_tuple(p.first, p.second).ptr());
96  }
97  static PyTypeObject const *get_pytype () {return &PyTuple_Type; }
98 };
99 
100 // Helper for convenience.
101 template <typename T1, typename T2>
102 struct std_pair_to_python_converter
103 {
104  std_pair_to_python_converter()
105  {
106  boost::python::to_python_converter<
107  std::pair<T1, T2>,
108  std_pair_to_tuple<T1, T2>,
109  true //std_pair_to_tuple has get_pytype
110  >();
111  }
112 };
113 
114 struct cv_vec3b_to_python_converter
115 {
116  static PyObject* convert(cv::Vec3b const& vec)
117  {
118  boost::python::list l;
119  l.append(boost::python::object(vec[0]));
120  l.append(boost::python::object(vec[1]));
121  l.append(boost::python::object(vec[2]));
122  return boost::python::incref(l.ptr());
123  }
124 };
125 
126 
128 #define MAKE_VECTOR_WRAPPER( CPP_NAME , PYTHON_NAME ) \
129  boost::python::class_< CPP_NAME >( #PYTHON_NAME ) \
130  .def(boost::python::vector_indexing_suite< CPP_NAME >()) \
131  ;
132 
133 
134 //vector item struct that allows Python to interact with std::vector
135 template<class T>
136 struct vector_item {
137  typedef typename T::value_type V;
138 
139  static V& get( T& x, int i )
140  {
141  if( i < 0 ) { i += x.size(); }
142  if( i >= 0 && (unsigned)i < x.size() ) { return x[i]; }
143  else { /*IndexError()*/; return x[0]; }
144  }
145  static void set( T& x, int i, V& v )
146  {
147  if( i < 0 ) { i += x.size(); }
148  if( i >= 0 && (unsigned)i < x.size() ) { x[i] = v; }
149  else { /*IndexError()*/; }
150  }
151  static void del( T& x, int i )
152  {
153  if( i < 0 ) { i += x.size(); }
154  if( i >= 0 && (unsigned)i < x.size() ) { x.erase( x.begin() + i ); }
155  else { /*IndexError()*/; }
156  }
157  static void add( T& x, V& v )
158  {
159  x.push_back( v );
160  }
161 
162  static bool in( T& x, V& v ) {
163  return find_eq( x.begin, x.end, v ) != x.end();
164  }
165  static int index( T& x, V& v ) {
166  int i = 0;
167  for( typename T::const_iterator it = x.begin; it != x.end(); ++it, ++i )
168  if( *it == v ) { return i; }
169  return -1;
170  }
171 };
172 
173 //define vector wrapper for Python - std::vector interoperability
174 #define MAKE_VECTOR_WRAPPER_LIMITED( CPP_NAME , PYTHON_NAME ) \
175  boost::python::class_< CPP_NAME >( #PYTHON_NAME ) \
176  .def("__len__" , & CPP_NAME::size) \
177  .def("clear" , & CPP_NAME::clear) \
178  .def("append" , & vector_item< CPP_NAME >::add \
179  , boost::python::with_custodian_and_ward<1, 2>()) \
180  .def("__setitem__" , & vector_item< CPP_NAME >::set \
181  , boost::python::with_custodian_and_ward<1, 2>()) \
182  .def("__getitem__" , & vector_item< CPP_NAME >::get \
183  , boost::python::return_value_policy<boost::python::copy_non_const_reference>()) \
184  .def("__delitem__" , & vector_item< CPP_NAME >::del) \
185  .def("__iter__" , boost::python::iterator< CPP_NAME >() ) \
186 ;
187 
188 #endif // PYTHON_UTILS_H