问题描述
我知道这个话题在互联网上被广泛讨论,但我找不到我的问题的答案......
所以我的最终目标是提取图像的一部分并将其与“模板”进行比较。 我已经提取并裁剪了图像的一部分,所以这不是问题。
我遇到的问题是试图将它与它的模板进行比较。模板最初是 SVG,所以我将其转换为 JPG 并删除了 alpha 通道。
实际图像取自网络摄像头,因此它是彩色的,但我可以轻松地设置阈值以仅保留黑色/白色。
所以我尝试了 3 种方法。
1. SIFT algorithm.
private void MatchBySift(Mat src1,Mat src2)
{
var gray1 = new Mat();
var gray2 = new Mat();
Cv2.CvtColor(src1,gray1,ColorConversionCodes.BGR2GRAY);
Cv2.CvtColor(src2,gray2,ColorConversionCodes.BGR2GRAY);
var sift = SIFT.Create();
// Detect the keypoints and generate their descriptors using SIFT
KeyPoint[] keypoints1,keypoints2;
var descriptors1 = new Mat(); //<float>
var descriptors2 = new Mat(); //<float>
sift.DetectAndCompute(gray1,null,out keypoints1,descriptors1);
sift.DetectAndCompute(gray2,out keypoints2,descriptors2);
// Match descriptor vectors
var bfMatcher = new BFMatcher(normTypes.L2,false);
var flannMatcher = new FlannBasedMatcher();
DMatch[] bfMatches;
DMatch[] flannMatches;
try
{
bfMatches = bfMatcher.Match(descriptors1,descriptors2);
flannMatches = flannMatcher.Match(descriptors1,descriptors2);
}
catch
{
bfMatches = new DMatch[0];
flannMatches = new DMatch[0];
}
// Draw matches
var bfView = new Mat();
Cv2.DrawMatches(gray1,keypoints1,keypoints2,bfMatches,bfView);
var flannView = new Mat();
Cv2.DrawMatches(gray1,flannMatches,flannView);
Console.WriteLine("BF Matches: " + bfMatches.Length);
Console.WriteLine("Flann Matches: " + flannMatches.Length);
using (new Window("SIFT matching (by BFMather)",bfView))
using (new Window("SIFT matching (by FlannBasedMatcher)",flannView))
{
Cv2.WaitKey();
}
}
2. SURF Algorithm
private void MatchBySurf(Mat src1,Mat src2)
{
var gray1 = new Mat();
var gray2 = new Mat();
Cv2.CvtColor(src1,ColorConversionCodes.BGR2GRAY);
Cv2.CvtColor(src2,ColorConversionCodes.BGR2GRAY);
var surf = SURF.Create(200,4,2,true);
// Detect the keypoints and generate their descriptors using SURF
KeyPoint[] keypoints1,keypoints2;
var descriptors1 = new Mat(); //<float>
var descriptors2 = new Mat(); //<float>
surf.DetectAndCompute(gray1,descriptors1);
surf.DetectAndCompute(gray2,descriptors2);
// Match descriptor vectors
var bfMatcher = new BFMatcher(normTypes.L2,false);
var flannMatcher = new FlannBasedMatcher();
DMatch[] bfMatches;
DMatch[] flannMatches;
try
{
bfMatches = bfMatcher.Match(descriptors1,descriptors2);
flannMatches = flannMatcher.Match(descriptors1,descriptors2);
}
catch
{
bfMatches = new DMatch[0];
flannMatches = new DMatch[0];
}
// Draw matches
var bfView = new Mat();
Cv2.DrawMatches(gray1,bfView);
var flannView = new Mat();
Cv2.DrawMatches(gray1,flannView);
Console.WriteLine("BF Matches: " + bfMatches.Length);
Console.WriteLine("Flann Matches: " + flannMatches.Length);
/*
using (new Window("SURF matching (by BFMather)",bfView))
using (new Window("SURF matching (by FlannBasedMatcher)",flannView))
{
Cv2.WaitKey();
}
*/
}
3. Hash comparison
private void MatchByHash(Mat src1,Mat src2)
{
Bitmap bit1 = BitmapConverter.ToBitmap(src1);
Bitmap bit2 = BitmapConverter.ToBitmap(src2);
List<bool> hash1 = GetHash(bit1);
List<bool> hash2 = GetHash(bit2);
int equalElements = hash1.Zip(hash2,(i,j) => i == j).Count(eq => eq);
Console.WriteLine("Match by Hash: " + equalElements);
}
public List<bool> GetHash(Bitmap bmpSource)
{
List<bool> lResult = new List<bool>();
//create new image with 16x16 pixel
Bitmap bmpMin = new Bitmap(bmpSource,new System.Drawing.Size(16,16));
for (int j = 0; j < bmpMin.Height; j++)
{
for (int i = 0; i < bmpMin.Width; i++)
{
//reduce colors to true / false
lResult.Add(bmpMin.GetPixel(i,j).GetBrightness() < 0.5f);
}
}
return lResult;
}
为什么我对结果不满意
- 筛选和冲浪
比较上面的图像时,我根据匹配的数量获得了一定的相似性。问题是当我使用不同的 template image
时,我总是得到相同的数字......我认为这是因为没有颜色,但我需要在这里澄清
- 哈希
在其他“模板”上使用时,我得到了更高的结果!这基本上消除了这种方法,除非它可以以某种方式改进......
我也听说过 ORB 算法,但我还没有尝试实现它。这对我来说会更好吗?
如果我可以尝试任何其他方法,请指出正确的方向!
谢谢
解决方法
主要是注册标志和模板。由于您的图像是准二进制的并且仅包含徽标,因此您可以依赖矩的计算。您将为二值化图像和二值化模板计算它们。
黑色像素的零阶矩是面积。面积比的平方根为您提供比例因子。
Y 时刻的一阶 X 为您提供参考点(质心)的位置,这在两者中都是相同的。
然后居中的二阶矩 (X²,Y²,XY) 将为您提供两个主要方向(通过计算惯性张量的特征向量),并由此得出徽标和模板之间的旋转角度。
https://www.ae.msstate.edu/vlsm/shape/area_moments_of_inertia/papmi.htm
现在您可以重新缩放、旋转和平移徽标或模板以叠加它们。您只需计算匹配颜色的像素即可获得比较分数。