You can do this, I've ported a very trivial subset of OpenCV into Go for my own purposes. In general, the process is to allocate everything on the heap and return it as a typedef'd void*
. For example:
typedef void* gocv_matrix;
From there, a lot of your work is passthrough functions. One very important note is that your header files must be in pure C and must only (recursively) include headers that are pure C. This means your headers are going to be mostly prototypes/forward declarations.
So a few Matrix methods in your header mat.h
may look like
gocv_matrix newMatrix();
void add(gocv_matrix m1, gocv_matrix m2, gocv_matrix dst);
void destroy(gocv_matrix m);
Then your implementation in mat.cxx
will look something like
//include all relevant C++ OpenCV headers directly
gocv_matrix newMatrix() {
cv::Matrix *mat = new cv::Matrix();
return (gocv_matrix)mat;
}
void add(gocv_matrix m1, gocv_matrix m2, gocv_matrix dst) {
cv::Matrix *a = (cv::Matrix *)m1;
cv::Matrix *b = (cv::Matrix *)m2;
cv::Matrix *dstMat = (cv::Matrix *)dst;
(*dstMat) = (*a)+(*b);
}
void destroy(gocv_matrix m) {
cv::Matrix *a = (cv::Matrix *)(m1);
delete a;
}
(Disclaimer: the exact code here isn't verified for correctness, this is just the gist).
A few special notes:
- Make sure you have a destroy method that you actually call or you'll leak memory.
- Since C and C++ constants aren't the same as Go constants, you'll have to declare them as
var
instead of const
.
- Some of OpenCV's constants are included in headers which aren't pure C, which makes it extremely difficult to define them within Go. I noticed this most with some image processing subpackages.
- Note the lack of templated generics. In general you're either foregoing templates entirely, defining a different type for each possible instance, or picking one (probably double, maybe an int size for displaying images) and sticking with it.
- Note that you can't use overloaded operators this way. So a+b*c is b.Mul(c).Add(a). In theory you could invent some expression parser that takes in a string like "a+(b*c)" and a list of matrices, and then does some call batching, but if you were at that point in development you wouldn't be asking this question.
- This is normal with cgo in general, but you'll probably be using unsafe a lot, especially if you want to work directly with the raw backing data of the matrix. You can reduce this somewhat by making your Go-level
Mytype
type a simple struct that contains a C.mytype
instead of actually converting it.
Honestly, you should probably just use SWIG, since this is basically already what it does for you anyway, in addition to extra niceties like generating actual Go constants for you in most cases instead of sketchy var magic.