0

Main goal: Make OpenCV work in Go without SWIG and third party lib (an application to compare image in linux using Go)

I am new in all the kits (OpenCv Go and linux)

  1. Can image detection (feature2d etc) can be done by C-api only? There is no convenient way to call C++ code and C-api is not updated(?)

  2. I have followed How to use C++ in Go? but I failed. When I make, I got the following errors

makefile:5: /usr/local/go/bin/src/Make.amd64: No such file or directory
makefile:6: /usr/local/go/bin/src/Make.pkg: No such file or directory
makefile:8: *
missing separator. Stop.

The makefile is as followed

GOROOT=/usr/local/go/bin  
   GOARCH=amd64  
   TARG=foo  
   CGOFILES=foo.go  
   include $(GOROOT)/src/Make.$(GOARCH)  
   include $(GOROOT)/src/Make.pkg  
   foo.o:foo.cpp  
   g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<  
   cfoo.o:cfoo.cpp  
   g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<  
   CGO_LDFLAGS+=-lstdc++  
   $(elem)_foo.so: foo.cgo4.o foo.o cfoo.o  
   gcc $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS)) -o $@ $^ $(CGO_LDFLAGS)  

Thanks a lot

Community
  • 1
  • 1
Eric
  • 1
  • 1

2 Answers2

1

You can't call C++ code without either writing C wrappers (+ cgo) yourself or using SWIG, that's just the way it is sadly.

That post you linked is extremely outdated and can't be used anymore.

On the other hand, you can always start rewriting opencv in pure go, the speed differences won't be that massive, specially if you learn how to use unsafe for the speed-critical parts.

disclaimer using unsafe is not advised since, well, it's unsafe.

OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • 1. Yes. I am working on wrapper but I have difficulties. Would you mind telling me the correct way? I have tried a lot but still can't find a workable solution. Thanks a lot. 2. "rewriting opencv in pure go", isn't this a tremendous work, compare to writing a wrapper? – Eric Sep 23 '14 at 17:30
  • @Eric yes I was just giving an example that you can do it. – OneOfOne Sep 23 '14 at 17:30
0

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.

Linear
  • 21,074
  • 4
  • 59
  • 70