From ad1f7142ec71bf2ff2ab281979476b7a608440db Mon Sep 17 00:00:00 2001 From: Bipeen Acharya Date: Mon, 8 Jul 2019 11:57:20 -0700 Subject: [PATCH] Add DistanceTransform and Watershed --- ROADMAP.md | 8 ++++---- imgproc.cpp | 8 ++++++++ imgproc.go | 43 ++++++++++++++++++++++++++++++++++++++++ imgproc.h | 2 ++ imgproc_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 5751e70b..995d51b6 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -63,11 +63,11 @@ Your pull requests will be greatly appreciated! - [ ] **Miscellaneous Image Transformations - WORK STARTED** The following functions still need implementation: - [ ] [cvtColorTwoPlane](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga8e873314e72a1a6c0252375538fbf753) - - [ ] [distanceTransform](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga8a0b7fdfcb7a13dde018988ba3a43042) + - [X] [distanceTransform](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga8a0b7fdfcb7a13dde018988ba3a43042) - [ ] [floodFill](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#gaf1f55a048f8a45bc3383586e80b1f0d0) - [ ] [grabCut](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga909c1dda50efcbeaa3ce126be862b37f) - [ ] [integral](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga97b87bec26908237e8ba0f6e96d23e28) - - [ ] [watershed](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga3267243e4d3f95165d55a618c65ac6e1) + - [X] [watershed](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga3267243e4d3f95165d55a618c65ac6e1) - [ ] **Drawing Functions - WORK STARTED** The following functions still need implementation: - [ ] [clipLine](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf483cb46ad6b049bc35ec67052ef1c2c) @@ -81,8 +81,8 @@ Your pull requests will be greatly appreciated! - [ ] Planar Subdivision - [ ] **Histograms - WORK STARTED** The following functions still need implementation: - [ ] [calcBackProject](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga3a0af640716b456c3d14af8aee12e3ca) - - [ ] [calcHist](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga4b2b5fd75503ff9e6844cc4dcdaed35d) - - [ ] [compareHist](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#gaf4190090efa5c47cb367cf97a9a519bd) + - [X] [calcHist](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga4b2b5fd75503ff9e6844cc4dcdaed35d) + - [X] [compareHist](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#gaf4190090efa5c47cb367cf97a9a519bd) - [ ] [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) diff --git a/imgproc.cpp b/imgproc.cpp index 04924b4b..17b2dc4c 100644 --- a/imgproc.cpp +++ b/imgproc.cpp @@ -115,6 +115,10 @@ void Dilate(Mat src, Mat dst, Mat kernel) { cv::dilate(*src, *dst, *kernel); } +void DistanceTransform(Mat src, Mat dst, Mat labels, int distanceType, int maskSize, int labelType) { + cv::distanceTransform(*src, *dst, *labels, distanceType, maskSize, labelType); +} + void Erode(Mat src, Mat dst, Mat kernel) { cv::erode(*src, *dst, *kernel); } @@ -432,6 +436,10 @@ void WarpPerspective(Mat src, Mat dst, Mat m, Size dsize) { cv::warpPerspective(*src, *dst, *m, sz); } +void Watershed(Mat image, Mat markers) { + cv::watershed(*image, *markers); +} + void ApplyColorMap(Mat src, Mat dst, int colormap) { cv::applyColorMap(*src, *dst, colormap); } diff --git a/imgproc.go b/imgproc.go index ec545695..5bc660b5 100644 --- a/imgproc.go +++ b/imgproc.go @@ -234,6 +234,41 @@ func Dilate(src Mat, dst *Mat, kernel Mat) { C.Dilate(src.p, dst.p, kernel.p) } +// DistanceTransformLabelTypes are the types of the DistanceTransform algorithm flag +type DistanceTransformLabelTypes int + +const ( + // DistanceLabelCComp assigns the same label to each connected component of zeros in the source image + // (as well as all the non-zero pixels closest to the connected component). + DistanceLabelCComp DistanceTransformLabelTypes = 0 + + // DistanceLabelPixel assigns its own label to each zero pixel (and all the non-zero pixels closest to it). + DistanceLabelPixel +) + +// DistanceTransformMasks are the marsk sizes for distance transform +type DistanceTransformMasks int + +const ( + // DistanceMask3 is a mask of size 3 + DistanceMask3 DistanceTransformMasks = 0 + + // DistanceMask5 is a mask of size 3 + DistanceMask5 + + // DistanceMaskPrecise is not currently supported + DistanceMaskPrecise +) + +// DistanceTransform Calculates the distance to the closest zero pixel for each pixel of the source image. +// +// For further details, please see: +// https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga8a0b7fdfcb7a13dde018988ba3a43042 +// +func DistanceTransform(src Mat, dst *Mat, labels *Mat, distType DistanceTypes, maskSize DistanceTransformMasks, labelType DistanceTransformLabelTypes) { + C.DistanceTransform(src.p, dst.p, labels.p, C.int(distType), C.int(maskSize), C.int(labelType)) +} + // Erode erodes an image by using a specific structuring element. // // For further details, please see: @@ -1316,6 +1351,14 @@ func WarpPerspective(src Mat, dst *Mat, m Mat, sz image.Point) { C.WarpPerspective(src.p, dst.p, m.p, pSize) } +// Watershed performs a marker-based image segmentation using the watershed algorithm. +// +// For further details, please see: +// https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga3267243e4d3f95165d55a618c65ac6e1 +func Watershed(image Mat, markers *Mat) { + C.Watershed(image.p, markers.p) +} + // ColormapTypes are the 12 GNU Octave/MATLAB equivalent colormaps. // // For further details, please see: diff --git a/imgproc.h b/imgproc.h index ffef4b72..41219fad 100644 --- a/imgproc.h +++ b/imgproc.h @@ -29,6 +29,7 @@ void Blur(Mat src, Mat dst, Size ps); void BoxFilter(Mat src, Mat dst, int ddepth, Size ps); void SqBoxFilter(Mat src, Mat dst, int ddepth, Size ps); void Dilate(Mat src, Mat dst, Mat kernel); +void DistanceTransform(Mat src, Mat dst, Mat labels, int distanceType, int maskSize, int labelType); void Erode(Mat src, Mat dst, Mat kernel); void MatchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask); struct Moment Moments(Mat src, bool binaryImage); @@ -84,6 +85,7 @@ void WarpAffine(Mat src, Mat dst, Mat rot_mat, Size dsize); void WarpAffineWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, Scalar borderValue); void WarpPerspective(Mat src, Mat dst, Mat m, Size dsize); +void Watershed(Mat image, Mat markers); void ApplyColorMap(Mat src, Mat dst, int colormap); void ApplyCustomColorMap(Mat src, Mat dst, Mat colormap); Mat GetPerspectiveTransform(Contour src, Contour dst); diff --git a/imgproc_test.go b/imgproc_test.go index d1b08546..f3ea2649 100644 --- a/imgproc_test.go +++ b/imgproc_test.go @@ -222,6 +222,33 @@ func TestDilate(t *testing.T) { } } +func TestDistanceTransform(t *testing.T) { + img := IMRead("images/face-detect.jpg", IMReadColor) + if img.Empty() { + t.Error("Invalid read of Mat in DistanceTransform test") + } + defer img.Close() + + gray := NewMat() + defer gray.Close() + CvtColor(img, &gray, ColorBGRToGray) + + threshImg := NewMat() + defer threshImg.Close() + Threshold(gray, &threshImg, 25, 255, ThresholdBinary) + + dest := NewMat() + defer dest.Close() + + labels := NewMat() + defer labels.Close() + + DistanceTransform(threshImg, &dest, &labels, DistL2, DistanceMask3, DistanceLabelCComp) + if dest.Empty() || dest.Rows() != img.Rows() || img.Cols() != dest.Cols() { + t.Error("Invalid DistanceTransform test") + } +} + func TestMatchTemplate(t *testing.T) { imgScene := IMRead("images/face.jpg", IMReadGrayScale) if imgScene.Empty() { @@ -1100,6 +1127,31 @@ func TestWarpAffineWithParamsGocvLogo(t *testing.T) { } } +func TestWatershed(t *testing.T) { + src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) + if src.Empty() { + t.Error("Invalid read of Mat in Watershed test") + } + defer src.Close() + + gray := NewMat() + defer gray.Close() + CvtColor(src, &gray, ColorBGRToGray) + + imgThresh := NewMat() + defer imgThresh.Close() + Threshold(gray, &imgThresh, 5, 50, ThresholdOtsu+ThresholdBinary) + + markers := NewMat() + defer markers.Close() + _ = ConnectedComponents(imgThresh, &markers) + + Watershed(src, &markers) + if markers.Empty() || src.Cols() != markers.Cols() || src.Rows() != markers.Rows() { + t.Error("Invalid Watershed test") + } +} + func TestApplyColorMap(t *testing.T) { type args struct { colormapType ColormapTypes