private void trainModel(String plantCategoryName, List <String> eachLeafSpecies) { BFMatcher match; if (!categoryBfmatcherMapping.ContainsKey(plantCategoryName)) { match = new BFMatcher(DistanceType.L2); categoryBfmatcherMapping.Add(plantCategoryName, match); } else { //Find values associated with key match = categoryBfmatcherMapping[plantCategoryName]; } foreach (String leaf in eachLeafSpecies) { using (Image <Bgr, Byte> image = loadImage(leaf)) { using (PreProcess preProcessAlgorithm = new PreProcess(image)) { using (Image <Hsv, Byte> HSVImage = preProcessAlgorithm._ImageToHSV()) { using (Image <Gray, Byte> grayScaleImage = preProcessAlgorithm._ImageToGrayScaleUsingConvert()) { using (FeatureExtractAlgorithm featureSet = new FeatureExtractAlgorithm(grayScaleImage)) { KeyPoints leafDescriptor = featureSet.SIFTDescriptor(); match.Add(leafDescriptor.Descriptor); } } } } } } }
public KeyPoints SIFTDescriptor() { KeyPoints result = new KeyPoints(); //SiFT Descriptor SIFT siftAlgo = null; VectorOfKeyPoint modelKeyPointsSift = null; try { siftAlgo = new SIFT(); modelKeyPointsSift = new VectorOfKeyPoint(); MKeyPoint[] siftPoints = siftAlgo.Detect(preProcessedImageInGrayScale); modelKeyPointsSift.Push(siftPoints); UMat siftDescriptors = new UMat(); siftAlgo.DetectAndCompute(preProcessedImageInGrayScale, null, modelKeyPointsSift, siftDescriptors, true); Image <Gray, Byte> outputImage = new Image <Gray, byte>( preProcessedImageInGrayScale.Width, preProcessedImageInGrayScale.Height); Features2DToolbox.DrawKeypoints( preProcessedImageInGrayScale, modelKeyPointsSift, outputImage, new Bgr(255, 255, 255), Features2DToolbox.KeypointDrawType.Default); string folderName = @"C:\Projects\LeafService\SiftImage"; string pathString = System.IO.Path.Combine(folderName, "Sift" + DateTime.UtcNow.Ticks); System.IO.Directory.CreateDirectory(pathString); if (Directory.Exists(pathString)) { string newFilePath = Path.Combine(pathString, "SiftImage" + DateTime.UtcNow.Ticks); outputImage.Save(folderName + ".jpg"); outputImage.Save(@"C:\Projects\LeafService\SIFTgray.jpg"); } //outputImage.Save("sift.jpg"); result.Descriptor = siftDescriptors; result.Points = siftPoints; return(result); } finally { siftAlgo.Dispose(); modelKeyPointsSift.Dispose(); } }
public MatcherResult knnMatch(KeyPoints queryDescriptor, BFMatcher matcher, string leafCategory, int distanceCutoff = int.MaxValue, PreProcessedImage trainingData = null) { MatcherResult result = new MatcherResult(); result.Category = leafCategory; using (VectorOfVectorOfDMatch vectorMatchesForSift = new VectorOfVectorOfDMatch()) { matcher.KnnMatch(queryDescriptor.Descriptor, vectorMatchesForSift, 2, null); int numberOfMatches = 0; Dictionary <int, int> counts = new Dictionary <int, int>(); List <MDMatch> goodMatches = new List <MDMatch>(vectorMatchesForSift.Size); for (int i = 0; i < vectorMatchesForSift.Size; i++) { // Do Ratio test: Reject matches where ratio of closest match with second closest if greater than 0.8 if ( (vectorMatchesForSift[i].Size == 1 || vectorMatchesForSift[i][0].Distance < 0.75 * vectorMatchesForSift[i][1].Distance) && vectorMatchesForSift[i][0].Distance < distanceCutoff) { goodMatches.Add(vectorMatchesForSift[i][0]); numberOfMatches++; } } //goodMatches = clusterBasedOnPoseEstimation(goodMatches, queryDescriptor, trainingData); int maxResults = int.MaxValue; result.MatchingPoints = goodMatches.Count; if (!goodMatches.Any()) { result.MatchDistance = float.MaxValue; result.AverageDistance = 0; result.MatchDistanceWeight = 0; result.MatchingPointsWeight = 0; } else { result.MatchDistance = goodMatches.OrderBy(item => item.Distance).Take(maxResults).Sum(item => item.Distance); result.AverageDistance = result.MatchDistance / result.MatchingPoints; result.MatchDistanceWeight = 1 / Math.Pow(result.AverageDistance, 2); result.MatchingPointsWeight = result.MatchingPoints * result.MatchingPoints; } } return(result); }
private void trainModel(String plantCategoryName, List <String> eachLeafSpecies) { BFMatcher match; if (!categoryBfmatcherMapping.ContainsKey(plantCategoryName)) { match = new BFMatcher(DistanceType.L1); categoryBfmatcherMapping.Add(plantCategoryName, match); } else { //Find values associated with key match = categoryBfmatcherMapping[plantCategoryName]; } foreach (String leaf in eachLeafSpecies) { PreProcess preProcessAlgorithm = null; FeatureExtractAlgorithm featureSet = null; try { //Console.WriteLine(leaf + "\n"); Image <Bgr, Byte> image = loadImage(leaf); preProcessAlgorithm = new PreProcess(image); //Image<Hsv, Byte> HSVImage = preProcessAlgorithm._ImageToHSV(); Image <Gray, Byte> grayScaleImage = preProcessAlgorithm._ImageToGrayScaleUsingConvert(); featureSet = new FeatureExtractAlgorithm(grayScaleImage); KeyPoints leafDescriptor = featureSet.SIFTDescriptor(); match.Add(leafDescriptor.Descriptor); } finally { if (preProcessAlgorithm != null) { preProcessAlgorithm.Dispose(); } if (featureSet != null) { featureSet.Dispose(); } } } }
public PreProcessedImage Execute(string imagePath, string category) { PreProcessedImage result = new PreProcessedImage(); result.FilePath = imagePath; result.Category = category; using (PreProcess preProcessAlgorithm = new PreProcess(new Image <Bgr, Byte>(imagePath))) using (Image <Gray, Byte> grayScaleImage = preProcessAlgorithm._ImageToGrayScaleUsingConvert()) { using (FeatureExtractAlgorithm featureSet = new FeatureExtractAlgorithm(grayScaleImage)) using (Mat canny = new Mat()) using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { KeyPoints descriptor = featureSet.SIFTDescriptor(); result.KeyPoints = descriptor; result.ContourArea = 0; CvInvoke.Canny(grayScaleImage, canny, 100, 50); int[,] hierarchy = CvInvoke.FindContourTree(canny, contours, ChainApproxMethod.ChainApproxSimple); result.NumberOfContours = contours.Size; double maxArea = double.MinValue; int maxIndex = -1; for (int index = 0; index < contours.Size; index++) { double area = CvInvoke.ContourArea(contours[index]); result.ContourArea += area; if (area > maxArea) { maxArea = area; maxIndex = index; } } result.Contour = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contours[maxIndex], result.Contour, CvInvoke.ArcLength(contours[maxIndex], true) * 0.02, true); return(result); } } }
public void startComparingImages(Dictionary <String, BFMatcher> categoryBfmatcherMapping) { using (PreProcess preProcessAlgorithm = new PreProcess(queryImage)) { using (Image <Gray, Byte> grayScaleImage = preProcessAlgorithm._ImageToGrayScaleUsingConvert()) { using (FeatureExtractAlgorithm featureSet = new FeatureExtractAlgorithm(grayScaleImage)) { using (KeyPoints leafDescriptor = featureSet.SIFTDescriptor()) { foreach (var pair in categoryBfmatcherMapping) { if (pair.Key == "abies_concolor") { continue; } try { DescriptorMatcher learningAlgo = new DescriptorMatcher(); BFMatcher bfmatch = pair.Value; string leafCategory = pair.Key; MatcherResult result = learningAlgo.knnMatch(leafDescriptor, bfmatch, leafCategory); finalResultSet.Add(result); } catch (Exception exception) { //TODO //Console.WriteLine(exception.ToString()); } } finalResultSet = finalResultSet.OrderByDescending(item => item, new MatcherResultComparer()).Take(3).ToList(); } } } } }
private List <MDMatch> clusterBasedOnPoseEstimation(List <MDMatch> matches, KeyPoints queryKeyPoints, PreProcessedImage trainingData) { // If no training data is provided then we cannot compute pose (LeafAnalysisV1), hence just return back the original set if (trainingData == null || matches == null || !matches.Any()) { return(matches); } Dictionary <MDMatch, List <MDMatch> > clusters = new Dictionary <MDMatch, List <MDMatch> >(matches.Count); List <PoseEstimate> poseEstimates = new List <PoseEstimate>(matches.Count); foreach (MDMatch match in matches) { MKeyPoint queryKeyPoint = queryKeyPoints.Points[match.QueryIdx]; MKeyPoint trainingKeyPoint = trainingData.KeyPoints.Points[match.TrainIdx]; PoseEstimate estimate = new PoseEstimate(); estimate.Match = match; estimate.Dx = trainingKeyPoint.Point.X - queryKeyPoint.Point.X; estimate.Dy = trainingKeyPoint.Point.Y - queryKeyPoint.Point.Y; estimate.Ds = trainingKeyPoint.Octave / queryKeyPoint.Octave; estimate.Do = trainingKeyPoint.Angle - queryKeyPoint.Angle; poseEstimates.Add(estimate); // Initialize clusters for each individual match // Next we will add other matches which belong to this cluster clusters.Add(match, new List <MDMatch>(new MDMatch[] { match })); } const double errorThreshold = 5; // Compute cluster membership foreach (PoseEstimate estimate in poseEstimates) { foreach (PoseEstimate otherEstimate in poseEstimates) { // Ignore self if (estimate == otherEstimate) { continue; } double error = estimate.RMSE(otherEstimate); //Console.WriteLine("Error: " + trainingData.Category + ": " + error); if (error < errorThreshold) { clusters[estimate.Match].Add(otherEstimate.Match); } } } // Finally pick the largest cluster List <MDMatch> result = null; int sizeOfCluster = -1;; foreach (KeyValuePair <MDMatch, List <MDMatch> > cluster in clusters) { if (cluster.Value.Count == sizeOfCluster) { // Tie breaker: choose the cluster with smaller overall distances if (result.Sum(item => item.Distance) > cluster.Value.Sum(item => item.Distance)) { result = cluster.Value; } } else if (cluster.Value.Count > sizeOfCluster) { sizeOfCluster = cluster.Value.Count; result = cluster.Value; } } return(result); }