From 70f4a77bf12f366a9fc4468a598842660ee962bc Mon Sep 17 00:00:00 2001 From: deadprogram Date: Thu, 19 Oct 2023 17:53:29 +0200 Subject: [PATCH] imgproc: add EMD() Signed-off-by: deadprogram --- ROADMAP.md | 3 +-- imgproc.cpp | 4 ++++ imgproc.go | 8 ++++++++ imgproc.h | 1 + imgproc_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index b8ec91d0..c2a91be6 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -68,8 +68,7 @@ Your pull requests will be greatly appreciated! - [ ] ColorMaps in OpenCV - [ ] Planar Subdivision - [ ] **Histograms - WORK STARTED** The following functions still need implementation: - - [ ] [EMD](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga902b8e60cc7075c8947345489221e0e0) - - [ ] [wrapperEMD](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga31fdda0864e64ca6b9de252a2611758b) + - [X] [EMD](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga902b8e60cc7075c8947345489221e0e0) - [ ] **Structural Analysis and Shape Descriptors - WORK STARTED** The following functions still need implementation: - [ ] [fitEllipse](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaf259efaad93098103d6c27b9e4900ffa) diff --git a/imgproc.cpp b/imgproc.cpp index f2da39a0..3d4c1137 100644 --- a/imgproc.cpp +++ b/imgproc.cpp @@ -76,6 +76,10 @@ double CompareHist(Mat hist1, Mat hist2, int method) { return cv::compareHist(*hist1, *hist2, method); } +float EMD(Mat sig1, Mat sig2, int distType) { + return cv::EMD(*sig1, *sig2, distType); +} + struct RotatedRect FitEllipse(PointVector pts) { cv::RotatedRect bRect = cv::fitEllipse(*pts); diff --git a/imgproc.go b/imgproc.go index 07d1e9cd..ff2bf96d 100644 --- a/imgproc.go +++ b/imgproc.go @@ -176,6 +176,14 @@ func CompareHist(hist1 Mat, hist2 Mat, method HistCompMethod) float32 { return float32(C.CompareHist(hist1.p, hist2.p, C.int(method))) } +// EMD Computes the "minimal work" distance between two weighted point configurations. +// +// For further details, please see: +// https://docs.opencv.org/4.x/d6/dc7/group__imgproc__hist.html#ga902b8e60cc7075c8947345489221e0e0 +func EMD(signature1, signature2 Mat, typ DistanceTypes) float32 { + return float32(C.EMD(signature1.p, signature2.p, C.int(typ))) +} + // ClipLine clips the line against the image rectangle. // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf483cb46ad6b049bc35ec67052ef1c2c diff --git a/imgproc.h b/imgproc.h index 9d67517e..5578432c 100644 --- a/imgproc.h +++ b/imgproc.h @@ -23,6 +23,7 @@ void EqualizeHist(Mat src, Mat dst); void CalcHist(struct Mats mats, IntVector chans, Mat mask, Mat hist, IntVector sz, FloatVector rng, bool acc); void CalcBackProject(struct Mats mats, IntVector chans, Mat hist, Mat backProject, FloatVector rng, bool uniform); double CompareHist(Mat hist1, Mat hist2, int method); +float EMD(Mat sig1, Mat sig2, int distType); void ConvexHull(PointVector points, Mat hull, bool clockwise, bool returnPoints); void ConvexityDefects(PointVector points, Mat hull, Mat result); void BilateralFilter(Mat src, Mat dst, int d, double sc, double ss); diff --git a/imgproc_test.go b/imgproc_test.go index d85bcefb..d231b353 100644 --- a/imgproc_test.go +++ b/imgproc_test.go @@ -1412,6 +1412,52 @@ func TestCompareHist(t *testing.T) { } +func TestEMD(t *testing.T) { + img := IMRead("images/face-detect.jpg", IMReadUnchanged) + if img.Empty() { + t.Error("Invalid read of Mat in CompareHist test") + } + defer img.Close() + + hist1 := NewMat() + defer hist1.Close() + + hist2 := NewMat() + defer hist2.Close() + + mask := NewMat() + defer mask.Close() + + CalcHist([]Mat{img}, []int{0, 1}, mask, &hist1, []int{30, 32}, []float64{0.0, 180.0, 0.0, 255.0}, false) + CalcHist([]Mat{img}, []int{0, 1}, mask, &hist2, []int{30, 32}, []float64{0.0, 180.0, 0.0, 255.0}, false) + + sig1 := NewMatWithSize(30*32, 3, MatTypeCV32FC1) + defer sig1.Close() + + sig2 := NewMatWithSize(30*32, 3, MatTypeCV32FC1) + defer sig2.Close() + + for h := 0; h < 30; h++ { + for s := 0; s < 32; s++ { + val := hist1.GetFloatAt(h, s) + sig1.SetFloatAt(h*32+s, 0, val) + sig1.SetFloatAt(h*32+s, 1, float32(h)) + sig1.SetFloatAt(h*32+s, 2, float32(s)) + + val = hist2.GetFloatAt(h, s) + sig2.SetFloatAt(h*32+s, 0, val) + sig2.SetFloatAt(h*32+s, 1, float32(h)) + sig2.SetFloatAt(h*32+s, 2, float32(s)) + } + } + + sim := EMD(sig1, sig2, DistL2) + if (1-sim)*100 < 99.9 { + t.Error("Invalid EMD test", (1-sim)*100) + } + +} + func TestDrawing(t *testing.T) { img := NewMatWithSize(150, 150, MatTypeCV8U) if img.Empty() {