我有一张钻石卡的图片和一张钻石的小图片,我想找到大图片中的所有钻石
以下是图片:
下面是实验代码:
using System.Collections.Generic;
using System;
using OpenCvSharp;
using OpenCvSharp.Features2D;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var src = new Mat("8_diamonds.png");
var templ = new Mat("diamonds_template.png");
var dst = new Mat();
SiftDetector(src, templ, dst, 0, 3, 0.04, 10, 0.6, 1.75);
Cv2.ImShow("dst", dst);
Cv2.ImShow("src", src);
Cv2.ImShow("templ", templ);
Cv2.WaitKey();
}
private static Scalar[] _Scalars = new[]
{
new Scalar(255, 0, 0),
new Scalar(0, 255, 0),
new Scalar(0, 0, 255),
new Scalar(255, 255, 0),
new Scalar(0, 255, 255),
new Scalar(255, 0, 255),
};
public static void SiftDetector(Mat src, Mat templ, Mat dst,
int nFeatures = 0,
int nOctaveLayers = 3,
double contrastThreshold = 0.04,
double edgeThreshold = 10,
double sigma = 1.6,
double ratio_thresh = 0.75)
{
var detector = SIFT.Create(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);
var descriptors_templ = new Mat();
var descriptors_src = new Mat();
detector.DetectAndCompute(templ, null, out var keypoints_templ, descriptors_templ);
detector.DetectAndCompute(src, null, out var keypoints_src, descriptors_src);
var matcher = new FlannBasedMatcher();
src.CopyTo(dst);
if (dst.Channels() == 1)
{
Cv2.CvtColor(dst, dst, ColorConversionCodes.GRAY2BGR);
}
for (int j = 0; j < 5; j++)
{
var knn_matches = matcher.KnnMatch(descriptors_templ, descriptors_src, 2);
//-- Filter matches using the Lowe's ratio test
var good_matches = new List<DMatch>();
for (var i = 0; i < knn_matches.Length; i++)
{
if (knn_matches[i][0].Distance < ratio_thresh * knn_matches[i][1].Distance)
{
good_matches.Add(knn_matches[i][0]);
}
}
if (good_matches.Count < 4)
{
break;
}
var dstPts = new List<Point2d>();
var srcPts = new List<Point2d>();
for (var i = 0; i < good_matches.Count; i++)
{
dstPts.Add(keypoints_templ[good_matches[i].QueryIdx].Pt.ToPoint2d());
srcPts.Add(keypoints_src[good_matches[i].TrainIdx].Pt.ToPoint2d());
}
Mat H = Cv2.FindHomography(dstPts, srcPts, HomographyMethods.Ransac);
if (H.Cols != 0)
{
var obj_corners = new Point2d[4];
obj_corners[0] = new Point2d(0, 0);
obj_corners[1] = new Point2d(templ.Cols, 0);
obj_corners[2] = new Point2d(templ.Cols, templ.Rows);
obj_corners[3] = new Point2d(0, templ.Rows);
var scene_corners = Cv2.PerspectiveTransform(obj_corners, H);
var drawingPoints = scene_corners.Select(p => (Point)p).ToArray();
Cv2.Polylines(dst, new[] { drawingPoints }, true, Scalar.Lime, 4);
}
foreach (var match in srcPts)
{
dst.Circle(match.ToPoint(), 5, _Scalars[j % _Scalars.Length], 2);
}
var toRemove = good_matches.Select(p => p.TrainIdx).Distinct().ToList();
foreach (var row in toRemove)
{
descriptors_src.Row(row).SetTo(new Scalar(float.MaxValue, float.MaxValue, float.MaxValue));
}
}
}
}
static class Extentions
{
public static Point2d ToPoint2d(this Point2f point2F)
{
return new Point2d(point2F.X, point2F.Y);
}
}
}
在这段代码中,我搜索匹配项,在找到的对象周围绘制,然后删除匹配项并再次搜索。
结果是:
问题是我如何找到所有的钻石,而不仅仅是第一颗?
SIFT
不是必需的,SURF
或任何类似的算法也是可能的。
使用 Python 的答案也将不胜感激。