diff --git a/src/OpenCvSharp/OpenCvSharp.csproj b/src/OpenCvSharp/OpenCvSharp.csproj
index 2c5f1d3d3..e552e8d0a 100644
--- a/src/OpenCvSharp/OpenCvSharp.csproj
+++ b/src/OpenCvSharp/OpenCvSharp.csproj
@@ -92,6 +92,9 @@
+
+
+
@@ -135,6 +138,7 @@
+
@@ -363,6 +367,7 @@
+
diff --git a/src/OpenCvSharp/PInvoke/NativeMethods_stdvector.cs b/src/OpenCvSharp/PInvoke/NativeMethods_stdvector.cs
index 4a1d122f2..6e1f60616 100644
--- a/src/OpenCvSharp/PInvoke/NativeMethods_stdvector.cs
+++ b/src/OpenCvSharp/PInvoke/NativeMethods_stdvector.cs
@@ -234,6 +234,22 @@ static partial class NativeMethods
[DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
public static extern void vector_DMatch_delete(IntPtr vector);
#endregion
+ #region vector
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr vector_vector_int_new1();
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr vector_vector_int_new2(IntPtr size);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr vector_vector_int_getSize1(IntPtr vector);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void vector_vector_int_getSize2(IntPtr vector, [In, Out] IntPtr[] size);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr vector_vector_int_getPointer(IntPtr vector);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void vector_vector_int_copy(IntPtr vec, IntPtr[] dst);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void vector_vector_int_delete(IntPtr vector);
+ #endregion
#region vector
[DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr vector_vector_float_new1();
diff --git a/src/OpenCvSharp/PInvoke/features2d/NativeMethods_features2d_BOW.cs b/src/OpenCvSharp/PInvoke/features2d/NativeMethods_features2d_BOW.cs
new file mode 100644
index 000000000..247db2570
--- /dev/null
+++ b/src/OpenCvSharp/PInvoke/features2d/NativeMethods_features2d_BOW.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 1591
+
+namespace OpenCvSharp
+{
+ static partial class NativeMethods
+ {
+ // ReSharper disable InconsistentNaming
+
+ // BOWTrainer
+
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWTrainer_add(IntPtr obj, IntPtr descriptors);
+
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWTrainer_getDescriptors(IntPtr obj, IntPtr descriptors);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int features2d_BOWTrainer_descriptorsCount(IntPtr obj);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWTrainer_clear(IntPtr obj);
+
+
+ // BOWKMeansTrainer
+
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr features2d_BOWKMeansTrainer_new(
+ int clusterCount, TermCriteria termcrit, int attempts, int flags);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWKMeansTrainer_delete(IntPtr obj);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr features2d_BOWKMeansTrainer_cluster1(IntPtr obj);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr features2d_BOWKMeansTrainer_cluster2(IntPtr obj, IntPtr descriptors);
+
+
+ // BOWImgDescriptorExtractor
+
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr features2d_BOWImgDescriptorExtractor_new1(IntPtr dextractor, IntPtr dmatcher);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr features2d_BOWImgDescriptorExtractor_new2(IntPtr dmatcher);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWImgDescriptorExtractor_delete(IntPtr obj);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWImgDescriptorExtractor_setVocabulary(IntPtr obj, IntPtr vocabulary);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr features2d_BOWImgDescriptorExtractor_getVocabulary(IntPtr obj);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWImgDescriptorExtractor_compute11(
+ IntPtr obj, IntPtr image, IntPtr keypoints, IntPtr imgDescriptor,
+ IntPtr pointIdxsOfClusters, IntPtr descriptors);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWImgDescriptorExtractor_compute12(
+ IntPtr obj, IntPtr keypointDescriptors,
+ IntPtr imgDescriptor, IntPtr pointIdxsOfClusters);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void features2d_BOWImgDescriptorExtractor_compute2(
+ IntPtr obj, IntPtr image, IntPtr keypoints, IntPtr imgDescriptor);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int features2d_BOWImgDescriptorExtractor_descriptorSize(IntPtr obj);
+ [DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int features2d_BOWImgDescriptorExtractor_descriptorType(IntPtr obj);
+ }
+}
diff --git a/src/OpenCvSharp/Vector/VectorOfVectorInt.cs b/src/OpenCvSharp/Vector/VectorOfVectorInt.cs
new file mode 100644
index 000000000..56b65c9f6
--- /dev/null
+++ b/src/OpenCvSharp/Vector/VectorOfVectorInt.cs
@@ -0,0 +1,137 @@
+using System;
+using OpenCvSharp.Util;
+
+namespace OpenCvSharp
+{
+ ///
+ ///
+ ///
+ internal class VectorOfVectorInt : DisposableCvObject, IStdVector
+ {
+ ///
+ /// Track whether Dispose has been called
+ ///
+ private bool disposed = false;
+
+ #region Init and Dispose
+
+ ///
+ ///
+ ///
+ public VectorOfVectorInt()
+ {
+ ptr = NativeMethods.vector_vector_int_new1();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public VectorOfVectorInt(int size)
+ {
+ if (size < 0)
+ throw new ArgumentOutOfRangeException(nameof(size));
+ ptr = NativeMethods.vector_vector_int_new2(new IntPtr(size));
+ }
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ ///
+ /// If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and unmanaged resources can be disposed.
+ /// If false, the method has been called by the runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ try
+ {
+ if (IsEnabledDispose)
+ {
+ NativeMethods.vector_vector_int_delete(ptr);
+ }
+ disposed = true;
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// vector.size()
+ ///
+ public int Size1
+ {
+ get { return NativeMethods.vector_vector_int_getSize1(ptr).ToInt32(); }
+ }
+
+ public int Size
+ {
+ get { return Size1; }
+ }
+
+ ///
+ /// vector[i].size()
+ ///
+ public long[] Size2
+ {
+ get
+ {
+ int size1 = Size1;
+ IntPtr[] size2Org = new IntPtr[size1];
+ NativeMethods.vector_vector_int_getSize2(ptr, size2Org);
+ long[] size2 = new long[size1];
+ for (int i = 0; i < size1; i++)
+ {
+ size2[i] = size2Org[i].ToInt64();
+ }
+ return size2;
+ }
+ }
+
+
+ ///
+ /// &vector[0]
+ ///
+ public IntPtr ElemPtr
+ {
+ get { return NativeMethods.vector_vector_int_getPointer(ptr); }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Converts std::vector to managed array
+ ///
+ ///
+ public int[][] ToArray()
+ {
+ int size1 = Size1;
+ if (size1 == 0)
+ return new int[0][];
+ long[] size2 = Size2;
+
+ var ret = new int[size1][];
+ for (int i = 0; i < size1; i++)
+ {
+ ret[i] = new int[size2[i]];
+ }
+ using (var retPtr = new ArrayAddress2(ret))
+ {
+ NativeMethods.vector_vector_int_copy(ptr, retPtr);
+ }
+ return ret;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/OpenCvSharp/modules/features2d/BOWImgDescriptorExtractor.cs b/src/OpenCvSharp/modules/features2d/BOWImgDescriptorExtractor.cs
new file mode 100644
index 000000000..5787d6d43
--- /dev/null
+++ b/src/OpenCvSharp/modules/features2d/BOWImgDescriptorExtractor.cs
@@ -0,0 +1,212 @@
+using System;
+
+namespace OpenCvSharp
+{
+ // ReSharper disable once InconsistentNaming
+
+ ///
+ /// Brute-force descriptor matcher.
+ /// For each descriptor in the first set, this matcher finds the closest descriptor in the second set by trying each one.
+ ///
+ public class BOWImgDescriptorExtractor : DisposableCvObject
+ {
+ ///
+ /// The constructor.
+ ///
+ /// Descriptor extractor that is used to compute descriptors for an input image and its keypoints.
+ /// Descriptor matcher that is used to find the nearest word of the trained vocabulary for each keypoint descriptor of the image.
+ public BOWImgDescriptorExtractor(Feature2D dextractor, DescriptorMatcher dmatcher)
+ {
+ if (dextractor == null)
+ throw new ArgumentNullException(nameof(dextractor));
+ if (dmatcher == null)
+ throw new ArgumentNullException(nameof(dmatcher));
+ ptr = NativeMethods.features2d_BOWImgDescriptorExtractor_new1(dextractor.ptrObj.CvPtr,
+ dmatcher.detectorPtr.CvPtr);
+ }
+
+ ///
+ /// The constructor.
+ ///
+ /// Descriptor matcher that is used to find the nearest word of the trained vocabulary for each keypoint descriptor of the image.
+ public BOWImgDescriptorExtractor(DescriptorMatcher dmatcher)
+ {
+ if (dmatcher == null)
+ throw new ArgumentNullException(nameof(dmatcher));
+ ptr = NativeMethods.features2d_BOWImgDescriptorExtractor_new2(dmatcher.detectorPtr.CvPtr);
+ }
+
+#if LANG_JP
+///
+/// リソースの解放
+///
+///
+/// trueの場合は、このメソッドがユーザコードから直接が呼ばれたことを示す。マネージ・アンマネージ双方のリソースが解放される。
+/// falseの場合は、このメソッドはランタイムからファイナライザによって呼ばれ、もうほかのオブジェクトから参照されていないことを示す。アンマネージリソースのみ解放される。
+///
+#else
+ ///
+ /// Releases the resources
+ ///
+ ///
+ /// If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and unmanaged resources can be disposed.
+ /// If false, the method has been called by the runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
+ ///
+#endif
+ protected override void Dispose(bool disposing)
+ {
+ if (!IsDisposed)
+ {
+ try
+ {
+ // releases managed resources
+ if (disposing)
+ {
+ }
+ else
+ {
+ if (ptr != IntPtr.Zero)
+ NativeMethods.features2d_BOWImgDescriptorExtractor_delete(ptr);
+ ptr = IntPtr.Zero;
+ }
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+ }
+
+ ///
+ /// Sets a visual vocabulary.
+ ///
+ /// Vocabulary (can be trained using the inheritor of BOWTrainer ).
+ /// Each row of the vocabulary is a visual word(cluster center).
+ public void SetVocabulary(Mat vocabulary)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ if (vocabulary == null)
+ throw new ArgumentNullException(nameof(vocabulary));
+ NativeMethods.features2d_BOWImgDescriptorExtractor_setVocabulary(ptr, vocabulary.CvPtr);
+ GC.KeepAlive(vocabulary);
+ }
+
+ ///
+ /// Returns the set vocabulary.
+ ///
+ ///
+ public Mat GetVocabulary()
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ IntPtr p = NativeMethods.features2d_BOWImgDescriptorExtractor_getVocabulary(ptr);
+ return new Mat(p);
+ }
+
+ ///
+ /// Computes an image descriptor using the set visual vocabulary.
+ ///
+ /// Image, for which the descriptor is computed.
+ /// Keypoints detected in the input image.
+ /// Computed output image descriptor.
+ /// pointIdxsOfClusters Indices of keypoints that belong to the cluster.
+ /// This means that pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster(word of vocabulary) returned if it is non-zero.
+ /// Descriptors of the image keypoints that are returned if they are non-zero.
+ public void Compute(InputArray image, out KeyPoint[] keypoints, OutputArray imgDescriptor,
+ out int[][] pointIdxsOfClusters, Mat descriptors = null)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ if (image == null)
+ throw new ArgumentNullException(nameof(image));
+ if (imgDescriptor == null)
+ throw new ArgumentNullException(nameof(imgDescriptor));
+
+ using (var keypointsVec = new VectorOfKeyPoint())
+ using (var pointIdxsOfClustersVec = new VectorOfVectorInt())
+ {
+ NativeMethods.features2d_BOWImgDescriptorExtractor_compute11(ptr, image.CvPtr, keypointsVec.CvPtr,
+ imgDescriptor.CvPtr, pointIdxsOfClustersVec.CvPtr, Cv2.ToPtr(descriptors));
+ keypoints = keypointsVec.ToArray();
+ pointIdxsOfClusters = pointIdxsOfClustersVec.ToArray();
+ }
+ GC.KeepAlive(image);
+ GC.KeepAlive(imgDescriptor);
+ GC.KeepAlive(descriptors);
+ }
+
+ ///
+ /// Computes an image descriptor using the set visual vocabulary.
+ ///
+ /// Computed descriptors to match with vocabulary.
+ /// Computed output image descriptor.
+ /// Indices of keypoints that belong to the cluster.
+ /// This means that pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster(word of vocabulary) returned if it is non-zero.
+ public void Compute(InputArray keypointDescriptors, OutputArray imgDescriptor, out int[][] pointIdxsOfClusters)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ if (keypointDescriptors == null)
+ throw new ArgumentNullException(nameof(keypointDescriptors));
+ if (imgDescriptor == null)
+ throw new ArgumentNullException(nameof(imgDescriptor));
+
+ using (var pointIdxsOfClustersVec = new VectorOfVectorInt())
+ {
+ NativeMethods.features2d_BOWImgDescriptorExtractor_compute12(
+ ptr, keypointDescriptors.CvPtr, imgDescriptor.CvPtr, pointIdxsOfClustersVec.CvPtr);
+ pointIdxsOfClusters = pointIdxsOfClustersVec.ToArray();
+ }
+ GC.KeepAlive(keypointDescriptors);
+ GC.KeepAlive(imgDescriptor);
+ }
+
+ ///
+ /// Computes an image descriptor using the set visual vocabulary.
+ ///
+ /// Image, for which the descriptor is computed.
+ /// Keypoints detected in the input image.
+ /// Computed output image descriptor.
+ public void Compute2(Mat image, out KeyPoint[] keypoints, Mat imgDescriptor)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ if (image == null)
+ throw new ArgumentNullException(nameof(image));
+ if (imgDescriptor == null)
+ throw new ArgumentNullException(nameof(imgDescriptor));
+
+ using (var keypointsVec = new VectorOfKeyPoint())
+ {
+ NativeMethods.features2d_BOWImgDescriptorExtractor_compute2(
+ ptr, image.CvPtr, keypointsVec.CvPtr, imgDescriptor.CvPtr);
+ keypoints = keypointsVec.ToArray();
+ }
+ GC.KeepAlive(image);
+ GC.KeepAlive(imgDescriptor);
+ }
+
+ ///
+ /// Returns an image descriptor size if the vocabulary is set. Otherwise, it returns 0.
+ ///
+ ///
+ public int DescriptorSize()
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ return NativeMethods.features2d_BOWImgDescriptorExtractor_descriptorSize(ptr);
+ }
+
+ ///
+ /// Returns an image descriptor type.
+ ///
+ ///
+ public int DescriptorType()
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ return NativeMethods.features2d_BOWImgDescriptorExtractor_descriptorType(ptr);
+ }
+ }
+}
diff --git a/src/OpenCvSharp/modules/features2d/BOWKMeansTrainer.cs b/src/OpenCvSharp/modules/features2d/BOWKMeansTrainer.cs
new file mode 100644
index 000000000..a07374952
--- /dev/null
+++ b/src/OpenCvSharp/modules/features2d/BOWKMeansTrainer.cs
@@ -0,0 +1,97 @@
+using System;
+
+namespace OpenCvSharp
+{
+ // ReSharper disable once InconsistentNaming
+
+ ///
+ /// Brute-force descriptor matcher.
+ /// For each descriptor in the first set, this matcher finds the closest descriptor in the second set by trying each one.
+ ///
+ public class BOWKMeansTrainer : BOWTrainer
+ {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public BOWKMeansTrainer(int clusterCount, TermCriteria? termcrit = null,
+ int attempts = 3, KMeansFlags flags = KMeansFlags.PpCenters)
+ {
+ var termCritValue = termcrit.GetValueOrDefault(new TermCriteria());
+ ptr = NativeMethods.features2d_BOWKMeansTrainer_new(clusterCount, termCritValue, attempts, (int)flags);
+ }
+
+#if LANG_JP
+ ///
+ /// リソースの解放
+ ///
+ ///
+ /// trueの場合は、このメソッドがユーザコードから直接が呼ばれたことを示す。マネージ・アンマネージ双方のリソースが解放される。
+ /// falseの場合は、このメソッドはランタイムからファイナライザによって呼ばれ、もうほかのオブジェクトから参照されていないことを示す。アンマネージリソースのみ解放される。
+ ///
+#else
+ ///
+ /// Releases the resources
+ ///
+ ///
+ /// If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and unmanaged resources can be disposed.
+ /// If false, the method has been called by the runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
+ ///
+#endif
+ protected override void Dispose(bool disposing)
+ {
+ if (!IsDisposed)
+ {
+ try
+ {
+ // releases managed resources
+ if (disposing)
+ {
+ }
+ else
+ {
+ if (ptr != IntPtr.Zero)
+ NativeMethods.features2d_BOWKMeansTrainer_delete(ptr);
+ ptr = IntPtr.Zero;
+ }
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+ }
+
+ ///
+ /// Clusters train descriptors.
+ ///
+ ///
+ public override Mat Cluster()
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ IntPtr p = NativeMethods.features2d_BOWKMeansTrainer_cluster1(ptr);
+ return new Mat(p);
+ }
+
+ ///
+ /// Clusters train descriptors.
+ ///
+ /// Descriptors to cluster. Each row of the descriptors matrix is a descriptor. Descriptors are not added to the inner train descriptor set.
+ /// The vocabulary consists of cluster centers. So, this method returns the vocabulary. In the first variant of the method, train descriptors stored in the object
+ /// are clustered.In the second variant, input descriptors are clustered.
+ ///
+ public override Mat Cluster(Mat descriptors)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().Name);
+ descriptors.ThrowIfDisposed();
+ IntPtr p = NativeMethods.features2d_BOWKMeansTrainer_cluster2(ptr, descriptors.CvPtr);
+ GC.KeepAlive(descriptors);
+ return new Mat(p);
+ }
+ }
+}
diff --git a/src/OpenCvSharp/modules/features2d/BOWTrainer.cs b/src/OpenCvSharp/modules/features2d/BOWTrainer.cs
new file mode 100644
index 000000000..1e1330bc8
--- /dev/null
+++ b/src/OpenCvSharp/modules/features2d/BOWTrainer.cs
@@ -0,0 +1,71 @@
+using System;
+
+namespace OpenCvSharp
+{
+ // ReSharper disable once InconsistentNaming
+
+ ///
+ /// Brute-force descriptor matcher.
+ /// For each descriptor in the first set, this matcher finds the closest descriptor in the second set by trying each one.
+ ///
+ public abstract class BOWTrainer : DisposableCvObject
+ {
+ ///
+ /// Adds descriptors to a training set.
+ ///
+ /// descriptors Descriptors to add to a training set. Each row of the descriptors matrix is a descriptor.
+ /// The training set is clustered using clustermethod to construct the vocabulary.
+ public void Add(Mat descriptors)
+ {
+ if (descriptors == null)
+ throw new ArgumentNullException(nameof(descriptors));
+ NativeMethods.features2d_BOWTrainer_add(ptr, descriptors.CvPtr);
+ GC.KeepAlive(descriptors);
+ }
+
+ ///
+ /// Returns a training set of descriptors.
+ ///
+ ///
+ public Mat[] GetDescriptors()
+ {
+ using (var descriptors = new VectorOfMat())
+ {
+ NativeMethods.features2d_BOWTrainer_getDescriptors(ptr, descriptors.CvPtr);
+ return descriptors.ToArray();
+ }
+ }
+
+ ///
+ /// Returns the count of all descriptors stored in the training set.
+ ///
+ ///
+ public int DescriptorsCount()
+ {
+ return NativeMethods.features2d_BOWTrainer_descriptorsCount(ptr);
+ }
+
+ ///
+ ///
+ ///
+ public virtual void Clear()
+ {
+ NativeMethods.features2d_BOWTrainer_clear(ptr);
+ }
+
+ ///
+ /// Clusters train descriptors.
+ ///
+ ///
+ public abstract Mat Cluster();
+
+ ///
+ /// Clusters train descriptors.
+ ///
+ /// Descriptors to cluster. Each row of the descriptors matrix is a descriptor. Descriptors are not added to the inner train descriptor set.
+ /// The vocabulary consists of cluster centers. So, this method returns the vocabulary. In the first variant of the method, train descriptors stored in the object
+ /// are clustered.In the second variant, input descriptors are clustered.
+ ///
+ public abstract Mat Cluster(Mat descriptors);
+ }
+}
diff --git a/src/OpenCvSharp/modules/features2d/DescriptorMatcher.cs b/src/OpenCvSharp/modules/features2d/DescriptorMatcher.cs
index aa4d49f5a..489f6637b 100644
--- a/src/OpenCvSharp/modules/features2d/DescriptorMatcher.cs
+++ b/src/OpenCvSharp/modules/features2d/DescriptorMatcher.cs
@@ -15,7 +15,7 @@ public class DescriptorMatcher : Algorithm
///
///
///
- private Ptr detectorPtr;
+ internal Ptr detectorPtr;
#region Init & Disposal
diff --git a/src/OpenCvSharp/modules/features2d/Feature2D.cs b/src/OpenCvSharp/modules/features2d/Feature2D.cs
index 383065450..24dce1bde 100644
--- a/src/OpenCvSharp/modules/features2d/Feature2D.cs
+++ b/src/OpenCvSharp/modules/features2d/Feature2D.cs
@@ -14,7 +14,7 @@ public class Feature2D : Algorithm
///
/// cv::Ptr<Feature2D>
///
- private Ptr ptrObj;
+ internal Ptr ptrObj;
///
///
diff --git a/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj b/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj
index c6a2b6e7b..174346d73 100644
--- a/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj
+++ b/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj
@@ -362,6 +362,7 @@
+
diff --git a/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj.filters b/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj.filters
index 92fccfd60..185faa328 100644
--- a/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj.filters
+++ b/src/OpenCvSharpExtern/OpenCvSharpExtern.vcxproj.filters
@@ -273,6 +273,9 @@
Header Files\imgproc
+
+ Header Files\features2d
+
diff --git a/src/OpenCvSharpExtern/features2d_BOW.h b/src/OpenCvSharpExtern/features2d_BOW.h
new file mode 100644
index 000000000..c04081074
--- /dev/null
+++ b/src/OpenCvSharpExtern/features2d_BOW.h
@@ -0,0 +1,113 @@
+#ifndef _CPP_FEATURES2D_BOW_H_
+#define _CPP_FEATURES2D_BOW_H_
+
+#include "include_opencv.h"
+
+// BOWTrainer
+
+CVAPI(void) features2d_BOWTrainer_add(cv::BOWTrainer *obj, cv::Mat *descriptors)
+{
+ obj->add(*descriptors);
+}
+
+CVAPI(void) features2d_BOWTrainer_getDescriptors(cv::BOWTrainer *obj, std::vector *descriptors)
+{
+ const std::vector d = obj->getDescriptors();
+ std::copy(d.begin(), d.end(), std::back_inserter(*descriptors));
+}
+
+CVAPI(int) features2d_BOWTrainer_descriptorsCount(cv::BOWTrainer *obj)
+{
+ return obj->descriptorsCount();
+}
+
+CVAPI(void) features2d_BOWTrainer_clear(cv::BOWTrainer *obj)
+{
+ obj->clear();
+}
+
+
+// BOWKMeansTrainer
+
+CVAPI(cv::BOWKMeansTrainer*) features2d_BOWKMeansTrainer_new(
+ int clusterCount, MyCvTermCriteria termcrit, int attempts, int flags)
+{
+ return new cv::BOWKMeansTrainer(clusterCount, cpp(termcrit), attempts, flags);
+}
+
+CVAPI(void) features2d_BOWKMeansTrainer_delete(cv::BOWKMeansTrainer *obj)
+{
+ delete obj;
+}
+
+CVAPI(cv::Mat*) features2d_BOWKMeansTrainer_cluster1(cv::BOWKMeansTrainer *obj)
+{
+ cv::Mat m = obj->cluster();
+ return new cv::Mat(m);
+}
+CVAPI(cv::Mat*) features2d_BOWKMeansTrainer_cluster2(cv::BOWKMeansTrainer *obj, cv::Mat *descriptors)
+{
+ cv::Mat m = obj->cluster(*descriptors);
+ return new cv::Mat(m);
+}
+
+
+// BOWImgDescriptorExtractor
+
+CVAPI(cv::BOWImgDescriptorExtractor*) features2d_BOWImgDescriptorExtractor_new1(
+ cv::Ptr *dextractor, cv::Ptr *dmatcher)
+{
+ return new cv::BOWImgDescriptorExtractor(*dextractor, *dmatcher);
+}
+CVAPI(cv::BOWImgDescriptorExtractor*) features2d_BOWImgDescriptorExtractor_new2(
+ cv::Ptr *dmatcher)
+{
+ return new cv::BOWImgDescriptorExtractor(*dmatcher);
+}
+
+CVAPI(void) features2d_BOWImgDescriptorExtractor_delete(cv::BOWImgDescriptorExtractor *obj)
+{
+ delete obj;
+}
+
+CVAPI(void) features2d_BOWImgDescriptorExtractor_setVocabulary(cv::BOWImgDescriptorExtractor *obj, cv::Mat *vocabulary)
+{
+ obj->setVocabulary(*vocabulary);
+}
+CVAPI(cv::Mat*) features2d_BOWImgDescriptorExtractor_getVocabulary(cv::BOWImgDescriptorExtractor *obj)
+{
+ cv::Mat m = obj->getVocabulary();
+ return new cv::Mat(m);
+}
+
+CVAPI(void) features2d_BOWImgDescriptorExtractor_compute11(
+ cv::BOWImgDescriptorExtractor *obj, cv::_InputArray *image, std::vector *keypoints, cv::_OutputArray *imgDescriptor,
+ std::vector >* pointIdxsOfClusters, cv::Mat* descriptors)
+{
+ obj->compute(*image, *keypoints, *imgDescriptor, pointIdxsOfClusters, descriptors);
+}
+
+CVAPI(void) features2d_BOWImgDescriptorExtractor_compute12(
+ cv::BOWImgDescriptorExtractor *obj, cv::_InputArray *keypointDescriptors,
+ cv::_OutputArray *imgDescriptor, std::vector >* pointIdxsOfClusters)
+{
+ obj->compute(*keypointDescriptors, *imgDescriptor, pointIdxsOfClusters);
+}
+
+CVAPI(void) features2d_BOWImgDescriptorExtractor_compute2(
+ cv::BOWImgDescriptorExtractor *obj, cv::Mat *image, std::vector *keypoints, cv::Mat *imgDescriptor)
+{
+ obj->compute2(*image, *keypoints, *imgDescriptor);
+}
+
+CVAPI(int) features2d_BOWImgDescriptorExtractor_descriptorSize(cv::BOWImgDescriptorExtractor *obj)
+{
+ return obj->descriptorSize();
+}
+
+CVAPI(int) features2d_BOWImgDescriptorExtractor_descriptorType(cv::BOWImgDescriptorExtractor *obj)
+{
+ return obj->descriptorType();
+}
+
+#endif
diff --git a/src/OpenCvSharpExtern/std_vector.h b/src/OpenCvSharpExtern/std_vector.h
index 2624099ab..b0393b225 100644
--- a/src/OpenCvSharpExtern/std_vector.h
+++ b/src/OpenCvSharpExtern/std_vector.h
@@ -445,6 +445,46 @@ CVAPI(void) vector_DMatch_delete(vector* vector)
}
#pragma endregion
+#pragma region vector
+CVAPI(vector >*) vector_vector_int_new1()
+{
+ return new vector >;
+}
+CVAPI(vector >*) vector_vector_int_new2(size_t size)
+{
+ return new vector >(size);
+}
+CVAPI(size_t) vector_vector_int_getSize1(vector >* vec)
+{
+ return vec->size();
+}
+CVAPI(void) vector_vector_int_getSize2(vector >* vec, size_t *sizes)
+{
+ for (size_t i = 0; i < vec->size(); i++)
+ {
+ sizes[i] = vec->at(i).size();
+ }
+}
+CVAPI(vector*) vector_vector_int_getPointer(vector >* vec)
+{
+ return &(vec->at(0));
+}
+CVAPI(void) vector_vector_int_copy(vector > *vec, int **dst)
+{
+ for (size_t i = 0; i < vec->size(); i++)
+ {
+ vector &elem = vec->at(i);
+ void *src = &elem[0];
+ size_t length = sizeof(int) * elem.size();
+ memcpy(dst[i], src, length);
+ }
+}
+CVAPI(void) vector_vector_int_delete(vector >* vec)
+{
+ delete vec;
+}
+#pragma endregion
+
#pragma region vector
CVAPI(vector >*) vector_vector_float_new1()
{