/// <summary> /// /// </summary> /// <param name="featuresFinder"></param> /// <param name="image"></param> /// <param name="features"></param> /// <param name="mask"></param> public static void ComputeImageFeatures( Feature2D featuresFinder, InputArray image, out ImageFeatures features, InputArray?mask = null) { if (featuresFinder == null) { throw new ArgumentNullException(nameof(featuresFinder)); } if (image == null) { throw new ArgumentNullException(nameof(image)); } featuresFinder.ThrowIfDisposed(); image.ThrowIfDisposed(); var descriptorsMat = new Mat(); var keypointsVec = new VectorOfKeyPoint(); var wImageFeatures = new WImageFeatures { Keypoints = keypointsVec.CvPtr, Descriptors = descriptorsMat.CvPtr }; unsafe { NativeMethods.HandleException( NativeMethods.stitching_computeImageFeatures2( featuresFinder.CvPtr, image.CvPtr, &wImageFeatures, mask?.CvPtr ?? IntPtr.Zero)); } features = new ImageFeatures( wImageFeatures.ImgIdx, wImageFeatures.ImgSize, keypointsVec.ToArray(), descriptorsMat); GC.KeepAlive(featuresFinder); GC.KeepAlive(image); GC.KeepAlive(mask); GC.KeepAlive(descriptorsMat); }
/// <summary> /// Performs images matching. /// </summary> /// <param name="features1">First image features</param> /// <param name="features2">Second image features</param> /// <returns>Found matches</returns> public virtual MatchesInfo Apply( ImageFeatures features1, ImageFeatures features2) { ThrowIfDisposed(); if (features1 == null) { throw new ArgumentNullException(nameof(features1)); } if (features2 == null) { throw new ArgumentNullException(nameof(features2)); } if (features1.Descriptors == null) { throw new ArgumentException($"{nameof(features1)}.Descriptors == null", nameof(features1)); } if (features2.Descriptors == null) { throw new ArgumentException($"{nameof(features2)}.Descriptors == null", nameof(features1)); } features1.Descriptors.ThrowIfDisposed(); features2.Descriptors.ThrowIfDisposed(); using var keypointsVec1 = new VectorOfKeyPoint(features1.Keypoints); using var keypointsVec2 = new VectorOfKeyPoint(features2.Keypoints); var features1Cpp = new WImageFeatures { ImgIdx = features1.ImgIdx, ImgSize = features1.ImgSize, Keypoints = keypointsVec1.CvPtr, Descriptors = features1.Descriptors.CvPtr, }; var features2Cpp = new WImageFeatures { ImgIdx = features2.ImgIdx, ImgSize = features2.ImgSize, Keypoints = keypointsVec2.CvPtr, Descriptors = features2.Descriptors.CvPtr, }; using var matchesVec = new VectorOfDMatch(); using var inliersMaskVec = new VectorOfByte(); var h = new Mat(); NativeMethods.HandleException( NativeMethods.stitching_FeaturesMatcher_apply( ptr, ref features1Cpp, ref features2Cpp, out var srcImgIdx, out var dstImgIdx, matchesVec.CvPtr, inliersMaskVec.CvPtr, out var numInliers, h.CvPtr, out var confidence)); GC.KeepAlive(this); return(new MatchesInfo( srcImgIdx, dstImgIdx, matchesVec.ToArray(), inliersMaskVec.ToArray(), numInliers, h, confidence)); }
/// <summary> /// Performs images matching. /// </summary> /// <param name="features">Features of the source images</param> /// <param name="mask">Mask indicating which image pairs must be matched</param> /// <returns>Found pairwise matches</returns> public virtual MatchesInfo[] Apply( IEnumerable <ImageFeatures> features, Mat?mask = null) { if (features == null) { throw new ArgumentNullException(nameof(features)); } ThrowIfDisposed(); var featuresArray = features.CastOrToArray(); if (featuresArray.Length == 0) { throw new ArgumentException("Empty features array", nameof(features)); } var keypointVecs = new VectorOfKeyPoint?[featuresArray.Length]; var wImageFeatures = new WImageFeatures[featuresArray.Length]; try { for (int i = 0; i < featuresArray.Length; i++) { if (featuresArray[i].Descriptors == null) { throw new ArgumentException("features contain null descriptor mat", nameof(features)); } featuresArray[i].Descriptors.ThrowIfDisposed(); keypointVecs[i] = new VectorOfKeyPoint(); wImageFeatures[i] = new WImageFeatures { ImgIdx = featuresArray[i].ImgIdx, ImgSize = featuresArray[i].ImgSize, Keypoints = keypointVecs[i] !.CvPtr, Descriptors = featuresArray[i].Descriptors.CvPtr, }; } using var srcImgIndexVecs = new VectorOfInt32(); using var dstImgIndexVecs = new VectorOfInt32(); using var matchesVec = new VectorOfVectorDMatch(); using var inlinersMaskVec = new VectorOfVectorByte(); using var numInliersVecs = new VectorOfInt32(); using var hVecs = new VectorOfMat(); using var confidenceVecs = new VectorOfDouble(); NativeMethods.HandleException( NativeMethods.stitching_FeaturesMatcher_apply2( ptr, wImageFeatures, wImageFeatures.Length, mask?.CvPtr ?? IntPtr.Zero, srcImgIndexVecs.CvPtr, dstImgIndexVecs.CvPtr, matchesVec.CvPtr, inlinersMaskVec.CvPtr, numInliersVecs.CvPtr, hVecs.CvPtr, confidenceVecs.CvPtr )); var srcImgIndices = srcImgIndexVecs.ToArray(); var dstImgIndices = dstImgIndexVecs.ToArray(); var matches = matchesVec.ToArray(); var inlinersMasks = inlinersMaskVec.ToArray(); var numInliers = numInliersVecs.ToArray(); var hs = hVecs.ToArray(); var confidences = confidenceVecs.ToArray(); var result = new MatchesInfo[srcImgIndices.Length]; for (int i = 0; i < srcImgIndices.Length; i++) { result[i] = new MatchesInfo( srcImgIndices[i], dstImgIndices[i], matches[i], inlinersMasks[i], numInliers[i], hs[i], confidences[i]); } return(result); } finally { foreach (var vec in keypointVecs) { vec?.Dispose(); } GC.KeepAlive(this); } }
/// <summary> /// /// </summary> /// <param name="featuresFinder"></param> /// <param name="images"></param> /// <param name="features"></param> /// <param name="masks"></param> public static void ComputeImageFeatures( Feature2D featuresFinder, IEnumerable <Mat> images, out ImageFeatures[] features, IEnumerable <Mat>?masks = null) { if (featuresFinder == null) { throw new ArgumentNullException(nameof(featuresFinder)); } if (images == null) { throw new ArgumentNullException(nameof(images)); } featuresFinder.ThrowIfDisposed(); var imagesArray = images as Mat[] ?? images.ToArray(); if (imagesArray.Length == 0) { throw new ArgumentException("Empty array", nameof(images)); } var descriptorsMat = new Mat[imagesArray.Length]; var keypointsVec = new VectorOfKeyPoint[imagesArray.Length]; var wImageFeatures = new WImageFeatures[imagesArray.Length]; for (int i = 0; i < imagesArray.Length; i++) { descriptorsMat[i] = new Mat(); keypointsVec[i] = new VectorOfKeyPoint(); wImageFeatures[i] = new WImageFeatures { Keypoints = keypointsVec[i].CvPtr, Descriptors = descriptorsMat[i].CvPtr }; } var imagesPointers = imagesArray.Select(i => i.CvPtr).ToArray(); var masksPointers = masks?.Select(i => i.CvPtr).ToArray(); if (masksPointers != null && imagesPointers.Length != masksPointers.Length) { throw new ArgumentException("size of images != size of masks"); } var wImageFeaturesPointers = new GCHandle[wImageFeatures.Length]; try { for (int i = 0; i < wImageFeatures.Length; i++) { wImageFeaturesPointers[i] = GCHandle.Alloc(wImageFeatures[i], GCHandleType.Pinned); } if (masksPointers == null) { NativeMethods.HandleException( NativeMethods.stitching_computeImageFeatures1_2( featuresFinder.CvPtr, imagesPointers, imagesPointers.Length, wImageFeaturesPointers.Select(gch => gch.AddrOfPinnedObject()).ToArray(), IntPtr.Zero)); } else { NativeMethods.HandleException( NativeMethods.stitching_computeImageFeatures1_1( featuresFinder.CvPtr, imagesPointers, imagesPointers.Length, wImageFeaturesPointers.Select(gch => gch.AddrOfPinnedObject()).ToArray(), masksPointers)); } } finally { for (int i = 0; i < wImageFeaturesPointers.Length; i++) { wImageFeaturesPointers[i].Free(); } } features = new ImageFeatures[wImageFeatures.Length]; for (int i = 0; i < wImageFeaturesPointers.Length; i++) { features[i] = new ImageFeatures( wImageFeatures[i].ImgIdx, wImageFeatures[i].ImgSize, keypointsVec[i].ToArray(), descriptorsMat[i]); } GC.KeepAlive(featuresFinder); GC.KeepAlive(images); GC.KeepAlive(masks); GC.KeepAlive(descriptorsMat); GC.KeepAlive(imagesPointers); }