diff --git a/contrib/xfeatures2d.cpp b/contrib/xfeatures2d.cpp index 7197cf28..d1f3c179 100644 --- a/contrib/xfeatures2d.cpp +++ b/contrib/xfeatures2d.cpp @@ -1,47 +1,5 @@ #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 diff --git a/contrib/xfeatures2d.go b/contrib/xfeatures2d.go index 980d8c17..59590305 100644 --- a/contrib/xfeatures2d.go +++ b/contrib/xfeatures2d.go @@ -13,54 +13,6 @@ import ( "gocv.io/x/gocv" ) -// SIFT is a wrapper around the cv::SIFT algorithm. -// Due to being a patented algorithm you must set the OpenCV contrib build flag OPENCV_ENABLE_NONFREE=1 -// in order to use it. -type SIFT struct { - // C.SIFT - p unsafe.Pointer -} - -// NewSIFT returns a new SIFT algorithm. -// -// For further details, please see: -// https://docs.opencv.org/master/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/master/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())) - - return getKeyPoints(ret) -} - -// DetectAndCompute detects and computes keypoints in an image using SIFT. -// -// For further details, please see: -// https://docs.opencv.org/master/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())) - - return getKeyPoints(ret), desc -} - // SURF is a wrapper around the cv::SURF algorithm. // Due to being a patented algorithm you must set the OpenCV contrib build flag OPENCV_ENABLE_NONFREE=1 // in order to use it. diff --git a/contrib/xfeatures2d.h b/contrib/xfeatures2d.h index d9241074..e513a160 100644 --- a/contrib/xfeatures2d.h +++ b/contrib/xfeatures2d.h @@ -10,18 +10,11 @@ extern "C" { #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); diff --git a/contrib/xfeatures2d_test.go b/contrib/xfeatures2d_test.go index 26fd30f8..06eb54e9 100644 --- a/contrib/xfeatures2d_test.go +++ b/contrib/xfeatures2d_test.go @@ -7,42 +7,6 @@ import ( "gocv.io/x/gocv" ) -func TestSIFT(t *testing.T) { - testNonFree := os.Getenv("OPENCV_ENABLE_NONFREE") - if testNonFree == "" { - t.Skip("Skipping SIFT test since OPENCV_ENABLE_NONFREE was not set") - } - - 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) { testNonFree := os.Getenv("OPENCV_ENABLE_NONFREE") if testNonFree == "" { diff --git a/features2d.cpp b/features2d.cpp index 8e98c28a..fcf7a12b 100644 --- a/features2d.cpp +++ b/features2d.cpp @@ -428,3 +428,46 @@ void DrawKeyPoints(Mat src, struct KeyPoints kp, Mat dst, Scalar s, int flags) { cv::drawKeypoints(*src, keypts, *dst, color, static_cast(flags)); } + +SIFT SIFT_Create() { + // TODO: params + return new cv::Ptr(cv::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; +} diff --git a/features2d.go b/features2d.go index d401c3a6..a267c196 100644 --- a/features2d.go +++ b/features2d.go @@ -748,3 +748,50 @@ func DrawKeyPoints(src Mat, keyPoints []KeyPoint, dst *Mat, color color.RGBA, fl C.DrawKeyPoints(src.p, cKeyPoints, dst.p, scalar, C.int(flag)) } + +// SIFT is a wrapper around the cv::SIFT algorithm. +// Due to the patent having expired, this is now in the main OpenCV code modules. +type SIFT struct { + // C.SIFT + p unsafe.Pointer +} + +// NewSIFT returns a new SIFT algorithm. +// +// For further details, please see: +// https://docs.opencv.org/master/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/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 +// +func (d *SIFT) Detect(src Mat) []KeyPoint { + ret := C.SIFT_Detect((C.SIFT)(d.p), C.Mat(src.Ptr())) + + return getKeyPoints(ret) +} + +// DetectAndCompute detects and computes keypoints in an image using SIFT. +// +// For further details, please see: +// https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 +// +func (d *SIFT) DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) { + desc := NewMat() + ret := C.SIFT_DetectAndCompute((C.SIFT)(d.p), C.Mat(src.Ptr()), C.Mat(mask.Ptr()), + C.Mat(desc.Ptr())) + + return getKeyPoints(ret), desc +} diff --git a/features2d.h b/features2d.h index 8c68f93f..bba7a559 100644 --- a/features2d.h +++ b/features2d.h @@ -19,6 +19,7 @@ typedef cv::Ptr* MSER; typedef cv::Ptr* ORB; typedef cv::Ptr* SimpleBlobDetector; typedef cv::Ptr* BFMatcher; +typedef cv::Ptr* SIFT; #else typedef void* AKAZE; typedef void* AgastFeatureDetector; @@ -30,6 +31,7 @@ typedef void* MSER; typedef void* ORB; typedef void* SimpleBlobDetector; typedef void* BFMatcher; +typedef void* SIFT; #endif AKAZE AKAZE_Create(); @@ -82,6 +84,11 @@ struct MultiDMatches BFMatcher_KnnMatch(BFMatcher b, Mat query, Mat train, int k void DrawKeyPoints(Mat src, struct KeyPoints kp, Mat dst, const Scalar s, int flags); +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); + #ifdef __cplusplus } #endif diff --git a/features2d_test.go b/features2d_test.go index 21587d24..f1b4836a 100644 --- a/features2d_test.go +++ b/features2d_test.go @@ -453,3 +453,34 @@ func TestDrawKeyPoints(t *testing.T) { t.Error("Invalid DrawKeyPoints test") } } + +func TestSIFT(t *testing.T) { + img := IMRead("./images/face.jpg", IMReadGrayScale) + if img.Empty() { + t.Error("Invalid Mat in SIFT test") + } + defer img.Close() + + dst := 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 := 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") + } +} diff --git a/version_test.go b/version_test.go index d9742e56..eb877f0f 100644 --- a/version_test.go +++ b/version_test.go @@ -8,7 +8,7 @@ import ( func TestVersions(t *testing.T) { ocvv := OpenCVVersion() - if !strings.Contains(ocvv, "4.3") { + if !strings.Contains(ocvv, "4.4") { t.Error("Wrong version of OpenCV:", ocvv) }