diff --git a/.travis.yml b/.travis.yml index b911199c..a3601eb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ before_cache: script: - export CGO_CPPFLAGS="-I${HOME}/usr/include" - - export CGO_LDFLAGS="-L${HOME}/usr/lib -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video" + - export CGO_LDFLAGS="-L${HOME}/usr/lib -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video -lopencv_xfeatures2d" - echo "Ensuring code is well formatted"; ! gofmt -s -d . | read - go test -coverprofile=coverage.txt -covermode=atomic diff --git a/appveyor.yml b/appveyor.yml index 68f262b6..f99beed9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,7 +26,7 @@ install: - cd c:\gopath\src\gocv.io\x\gocv - go get -d . - set CGO_CPPFLAGS=-IC:\opencv\build\install\include - - set CGO_LDFLAGS=-LC:\opencv\build\install\x64\mingw\lib -lopencv_core331 -lopencv_videoio331 -lopencv_imgproc331 -lopencv_highgui331 -lopencv_imgcodecs331 -lopencv_objdetect331 -lopencv_features2d331 -lopencv_video331 + - set CGO_LDFLAGS=-LC:\opencv\build\install\x64\mingw\lib -lopencv_core331 -lopencv_videoio331 -lopencv_imgproc331 -lopencv_highgui331 -lopencv_imgcodecs331 -lopencv_objdetect331 -lopencv_features2d331 -lopencv_video331 -lopencv_xfeatures2d331 - go env build_script: diff --git a/contrib/README.md b/contrib/README.md new file mode 100644 index 00000000..ea2a7ba5 --- /dev/null +++ b/contrib/README.md @@ -0,0 +1,13 @@ +# Using OpenCV Contrib + +GoCV support for OpenCV's Contrib can be found here in the "gocv.io/x/gocv/contrib" package. + +For more information about OpenCV Contrib, please go to: + +https://github.com/opencv/opencv_contrib + +## How to use + +```go +// code here... +``` \ No newline at end of file diff --git a/contrib/contrib.go b/contrib/contrib.go new file mode 100644 index 00000000..544b14ee --- /dev/null +++ b/contrib/contrib.go @@ -0,0 +1,6 @@ +// Package contrib is the GoCV wrapper around OpenCV Contrib. +// +// For further details, please see: +// https://github.com/opencv/opencv_contrib +// +package contrib // import "gocv.io/x/gocv/contrib" diff --git a/contrib/xfeatures2d.cpp b/contrib/xfeatures2d.cpp new file mode 100644 index 00000000..b9bb0d99 --- /dev/null +++ b/contrib/xfeatures2d.cpp @@ -0,0 +1,75 @@ +#include "xfeatures2d.h" + +SIFT SIFT_Create() { + // TODO: params + return new cv::Ptr(cv::xfeatures2d::SIFT::create()); +} + +void SIFT_Close(SIFT d) { + delete d; +} + +struct KeyPoints SIFT_Detect(SIFT d, Mat src) { + std::vector detected; + (*d)->detect(*src, detected); + + KeyPoint* kps = new KeyPoint[detected.size()]; + for (size_t i = 0; i < detected.size(); ++i) { + KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, + detected[i].response, detected[i].octave, detected[i].class_id}; + kps[i] = k; + } + KeyPoints ret = {kps, (int)detected.size()}; + return ret; +} + +struct KeyPoints SIFT_DetectAndCompute(SIFT d, Mat src, Mat mask, Mat desc) { + std::vector detected; + (*d)->detectAndCompute(*src, *mask, detected, *desc); + + KeyPoint* kps = new KeyPoint[detected.size()]; + for (size_t i = 0; i < detected.size(); ++i) { + KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, + detected[i].response, detected[i].octave, detected[i].class_id}; + kps[i] = k; + } + KeyPoints ret = {kps, (int)detected.size()}; + return ret; +} + +SURF SURF_Create() { + // TODO: params + return new cv::Ptr(cv::xfeatures2d::SURF::create()); +} + +void SURF_Close(SURF d) { + delete d; +} + +struct KeyPoints SURF_Detect(SURF d, Mat src) { + std::vector detected; + (*d)->detect(*src, detected); + + KeyPoint* kps = new KeyPoint[detected.size()]; + for (size_t i = 0; i < detected.size(); ++i) { + KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, + detected[i].response, detected[i].octave, detected[i].class_id}; + kps[i] = k; + } + KeyPoints ret = {kps, (int)detected.size()}; + return ret; +} + +struct KeyPoints SURF_DetectAndCompute(SURF d, Mat src, Mat mask, Mat desc) { + std::vector detected; + (*d)->detectAndCompute(*src, *mask, detected, *desc); + + KeyPoint* kps = new KeyPoint[detected.size()]; + for (size_t i = 0; i < detected.size(); ++i) { + KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, + detected[i].response, detected[i].octave, detected[i].class_id}; + kps[i] = k; + } + KeyPoints ret = {kps, (int)detected.size()}; + return ret; +} diff --git a/contrib/xfeatures2d.go b/contrib/xfeatures2d.go new file mode 100644 index 00000000..fe98373e --- /dev/null +++ b/contrib/xfeatures2d.go @@ -0,0 +1,128 @@ +package contrib + +/* +#include +#include "xfeatures2d.h" +*/ +import "C" + +import ( + "reflect" + "unsafe" + + "gocv.io/x/gocv" +) + +// SIFT is a wrapper around the cv::SIFT algorithm. +type SIFT struct { + // C.SIFT + p unsafe.Pointer +} + +// NewSIFT returns a new SIFT algorithm. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d5/d3c/classcv_1_1xfeatures2d_1_1SIFT.html +// +func NewSIFT() SIFT { + return SIFT{p: unsafe.Pointer(C.SIFT_Create())} +} + +// Close SIFT. +func (d *SIFT) Close() error { + C.SIFT_Close((C.SIFT)(d.p)) + d.p = nil + return nil +} + +// Detect keypoints in an image using SIFT. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 +// +func (d *SIFT) Detect(src gocv.Mat) []gocv.KeyPoint { + ret := C.SIFT_Detect((C.SIFT)(d.p), C.Mat(src.Ptr())) + //defer C.KeyPoints_Close(ret) + + return getKeyPoints(ret) +} + +// DetectAndCompute detects and computes keypoints in an image using SIFT. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 +// +func (d *SIFT) DetectAndCompute(src gocv.Mat, mask gocv.Mat) ([]gocv.KeyPoint, gocv.Mat) { + desc := gocv.NewMat() + ret := C.SIFT_DetectAndCompute((C.SIFT)(d.p), C.Mat(src.Ptr()), C.Mat(mask.Ptr()), + C.Mat(desc.Ptr())) + //defer C.KeyPoints_Close(ret) + + return getKeyPoints(ret), desc +} + +// SURF is a wrapper around the cv::SURF algorithm. +type SURF struct { + // C.SURF + p unsafe.Pointer +} + +// NewSURF returns a new SURF algorithm. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d5/df7/classcv_1_1xfeatures2d_1_1SURF.html +// +func NewSURF() SURF { + return SURF{p: unsafe.Pointer(C.SURF_Create())} +} + +// Close SURF. +func (d *SURF) Close() error { + C.SURF_Close((C.SURF)(d.p)) + d.p = nil + return nil +} + +// Detect keypoints in an image using SURF. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 +// +func (d *SURF) Detect(src gocv.Mat) []gocv.KeyPoint { + ret := C.SURF_Detect((C.SURF)(d.p), C.Mat(src.Ptr())) + //defer C.KeyPoints_Close(ret) + + return getKeyPoints(ret) +} + +// DetectAndCompute detects and computes keypoints in an image using SURF. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 +// +func (d *SURF) DetectAndCompute(src gocv.Mat, mask gocv.Mat) ([]gocv.KeyPoint, gocv.Mat) { + desc := gocv.NewMat() + ret := C.SURF_DetectAndCompute((C.SURF)(d.p), C.Mat(src.Ptr()), C.Mat(mask.Ptr()), + C.Mat(desc.Ptr())) + //defer C.KeyPoints_Close(ret) + + return getKeyPoints(ret), desc +} + +func getKeyPoints(ret C.KeyPoints) []gocv.KeyPoint { + cArray := ret.keypoints + length := int(ret.length) + hdr := reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(cArray)), + Len: length, + Cap: length, + } + s := *(*[]C.KeyPoint)(unsafe.Pointer(&hdr)) + + keys := make([]gocv.KeyPoint, length) + for i, r := range s { + keys[i] = gocv.KeyPoint{float64(r.x), float64(r.y), float64(r.size), float64(r.angle), float64(r.response), + int(r.octave), int(r.classID)} + } + return keys +} diff --git a/contrib/xfeatures2d.h b/contrib/xfeatures2d.h new file mode 100644 index 00000000..d9241074 --- /dev/null +++ b/contrib/xfeatures2d.h @@ -0,0 +1,34 @@ +#ifndef _OPENCV3_XFEATURES2D_H_ +#define _OPENCV3_XFEATURES2D_H_ + +#ifdef __cplusplus +#include +#include +extern "C" { +#endif + +#include "../core.h" + +#ifdef __cplusplus +typedef cv::Ptr* SIFT; +typedef cv::Ptr* SURF; +#else +typedef void* SIFT; +typedef void* SURF; +#endif + +SIFT SIFT_Create(); +void SIFT_Close(SIFT f); +struct KeyPoints SIFT_Detect(SIFT f, Mat src); +struct KeyPoints SIFT_DetectAndCompute(SIFT f, Mat src, Mat mask, Mat desc); + +SURF SURF_Create(); +void SURF_Close(SURF f); +struct KeyPoints SURF_Detect(SURF f, Mat src); +struct KeyPoints SURF_DetectAndCompute(SURF f, Mat src, Mat mask, Mat desc); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_XFEATURES2D_H_ diff --git a/contrib/xfeatures2d_test.go b/contrib/xfeatures2d_test.go new file mode 100644 index 00000000..787941c1 --- /dev/null +++ b/contrib/xfeatures2d_test.go @@ -0,0 +1,69 @@ +package contrib + +import ( + "testing" + + "gocv.io/x/gocv" +) + +func TestSIFT(t *testing.T) { + img := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) + if img.Empty() { + t.Error("Invalid Mat in SIFT test") + } + defer img.Close() + + dst := gocv.NewMat() + defer dst.Close() + + si := NewSIFT() + defer si.Close() + + kp := si.Detect(img) + if len(kp) == 512 { + t.Errorf("Invalid KeyPoint array in SIFT test: %d", len(kp)) + } + + mask := gocv.NewMat() + defer mask.Close() + + kp2, desc := si.DetectAndCompute(img, mask) + if len(kp2) == 512 { + t.Errorf("Invalid KeyPoint array in SIFT DetectAndCompute: %d", len(kp2)) + } + + if desc.Empty() { + t.Error("Invalid Mat desc in SIFT DetectAndCompute") + } +} + +func TestSURF(t *testing.T) { + img := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) + if img.Empty() { + t.Error("Invalid Mat in SURF test") + } + defer img.Close() + + dst := gocv.NewMat() + defer dst.Close() + + si := NewSURF() + defer si.Close() + + kp := si.Detect(img) + if len(kp) == 512 { + t.Errorf("Invalid KeyPoint array in SURF Detect: %d", len(kp)) + } + + mask := gocv.NewMat() + defer mask.Close() + + kp2, desc := si.DetectAndCompute(img, mask) + if len(kp2) == 512 { + t.Errorf("Invalid KeyPoint array in SURF DetectAndCompute: %d", len(kp2)) + } + + if desc.Empty() { + t.Error("Invalid Mat desc in SURF DetectAndCompute") + } +} diff --git a/env.sh b/env.sh index 53abe411..ea519eae 100644 --- a/env.sh +++ b/env.sh @@ -3,17 +3,17 @@ if [[ "$uname_val" == "Darwin" ]]; then CVPATH=$(brew info opencv | sed -n "4p" | sed -e "s/ (.*//g") export CGO_CPPFLAGS="-I$CVPATH/include -I$CVPATH/include/opencv2" export CGO_CXXFLAGS="--std=c++1z -stdlib=libc++" - export CGO_LDFLAGS="-L$CVPATH/lib -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video" + export CGO_LDFLAGS="-L$CVPATH/lib -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video -lopencv_xfeatures2d" echo "Environment variables configured for OSX" elif [[ "$uname_val" == "Linux" ]]; then if [[ -f /etc/pacman.conf ]]; then export CGO_CPPFLAGS="-I/usr/include" export CGO_CXXFLAGS="--std=c++1z" - export CGO_LDFLAGS="-L/lib64 -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video" + export CGO_LDFLAGS="-L/lib64 -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video -lopencv_xfeatures2d" else export CGO_CPPFLAGS="-I/usr/local/include" export CGO_CXXFLAGS="--std=c++1z" - export CGO_LDFLAGS="-L/usr/local/lib -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video" + export CGO_LDFLAGS="-L/usr/local/lib -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video -lopencv_xfeatures2d" fi echo "Environment variables configured for Linux" else