现在,如果我想构建一个图像库,每个图像使用图像的SURF功能来找到给定图像的最佳匹配,我有哪些选择?我可以构建一棵树,而不是与我的库中的每个图像进行强力匹配吗?我很困惑,因为Emgu似乎正在构建某种树,但只在两个图像之间:
//Create a SURF Tracker using k-d Tree
SURFTracker tracker = new SURFTracker(modelFeatures);
我几乎阅读了网站上关于该主题的所有帖子,但无法理解如何开始。我还想使用直方图匹配 - 将每个RGB通道分成二进制位并比较标准化计数。如果我想根据RGB计数对搜索空间进行分区,而不是计算库中每个图像的欧氏距离,那么仍然意味着在R,G,B之一上进行分支 - 我不知道如何构建决策树。
我几天前才刚开始阅读这个主题,所以为我的天真道歉。
答案 0 :(得分:1)
您可以查看EMGU CV的TrafficSignRecognition。它与SURFFeature示例相同,但在现实生活中应用。它能够检测给定的图像是否与给定的图像匹配以及有多少图像。我尝试过这个。你可以看看它。
答案 1 :(得分:1)
SURFTracker似乎使用了OpenCV附带的FLANN(近似最近邻居快速库)库(因此也有Emgu绑定):
假设您希望比仅对每个图像执行上述过程更快,则必须为每个图像的每个描述符构建一个树,并将其放入FLANN索引中同时跟踪哪个描述符来自哪个图像(可能在一个单独的数组中)。
当给定图像时,您可以从中提取所有描述符,并将它们逐个匹配到FLANN树(这比为每个模板描述符集合使用不同的树更快)。因此,对于样本中的每个描述符X,您将获得来自图像Z的最相似的描述符Y.这些描述符可以用作类似图像的投票(参见http://en.wikipedia.org/wiki/Bag_of_words_model)。
然而,这种方法没有考虑点的空间一致性......但是也可以检查我们有投票的前k个图像(k <&lt; N,数字系统中的所有图像)。
答案 2 :(得分:1)
此代码生成每个图像的矩阵,将它们全部附加在一起,然后获取FLANN索引,对其进行KNN搜索,然后返回匹配。所有代码都在这里:
/// <summary>
/// Main method.
/// </summary>
public IList<IndecesMapping> Match()
{
string[] dbImages = {"1.jpg", "2.jpg", "3.jpg"};
string queryImage = "query.jpg";
IList<IndecesMapping> imap;
// compute descriptors for each image
var dbDescsList = ComputeMultipleDescriptors(dbImages, out imap);
// concatenate all DB images descriptors into single Matrix
Matrix<float> dbDescs = ConcatDescriptors(dbDescsList);
// compute descriptors for the query image
Matrix<float> queryDescriptors = ComputeSingleDescriptors(queryImage);
FindMatches(dbDescs, queryDescriptors, ref imap);
return imap;
}
/// <summary>
/// Computes image descriptors.
/// </summary>
/// <param name="fileName">Image filename.</param>
/// <returns>The descriptors for the given image.</returns>
public Matrix<float> ComputeSingleDescriptors(string fileName)
{
Matrix<float> descs;
using (Image<Gray, Byte> img = new Image<Gray, byte>(fileName))
{
VectorOfKeyPoint keyPoints = detector.DetectKeyPointsRaw(img, null);
descs = detector.ComputeDescriptorsRaw(img, null, keyPoints);
}
return descs;
}
/// <summary>
/// Convenience method for computing descriptors for multiple images.
/// On return imap is filled with structures specifying which descriptor ranges in the concatenated matrix belong to what image.
/// </summary>
/// <param name="fileNames">Filenames of images to process.</param>
/// <param name="imap">List of IndecesMapping to hold descriptor ranges for each image.</param>
/// <returns>List of descriptors for the given images.</returns>
public IList<Matrix<float>> ComputeMultipleDescriptors(string[] fileNames, out IList<IndecesMapping> imap)
{
imap = new List<IndecesMapping>();
IList<Matrix<float>> descs = new List<Matrix<float>>();
int r = 0;
for (int i = 0; i < fileNames.Length; i++)
{
var desc = ComputeSingleDescriptors(fileNames[i]);
descs.Add(desc);
imap.Add(new IndecesMapping()
{
fileName = fileNames[i],
IndexStart = r,
IndexEnd = r + desc.Rows - 1
});
r += desc.Rows;
}
return descs;
}
/// <summary>
/// Computes 'similarity' value (IndecesMapping.Similarity) for each image in the collection against our query image.
/// </summary>
/// <param name="dbDescriptors">Query image descriptor.</param>
/// <param name="queryDescriptors">Consolidated db images descriptors.</param>
/// <param name="images">List of IndecesMapping to hold the 'similarity' value for each image in the collection.</param>
public void FindMatches(Matrix<float> dbDescriptors, Matrix<float> queryDescriptors, ref IList<IndecesMapping> imap)
{
var indices = new Matrix<int>(queryDescriptors.Rows, 2); // matrix that will contain indices of the 2-nearest neighbors found
var dists = new Matrix<float>(queryDescriptors.Rows, 2); // matrix that will contain distances to the 2-nearest neighbors found
// create FLANN index with 4 kd-trees and perform KNN search over it look for 2 nearest neighbours
var flannIndex = new Index(dbDescriptors, 4);
flannIndex.KnnSearch(queryDescriptors, indices, dists, 2, 24);
for (int i = 0; i < indices.Rows; i++)
{
// filter out all inadequate pairs based on distance between pairs
if (dists.Data[i, 0] < (0.6 * dists.Data[i, 1]))
{
// find image from the db to which current descriptor range belongs and increment similarity value.
// in the actual implementation this should be done differently as it's not very efficient for large image collections.
foreach (var img in imap)
{
if (img.IndexStart <= i && img.IndexEnd >= i)
{
img.Similarity++;
break;
}
}
}
}
}
/// <summary>
/// Concatenates descriptors from different sources (images) into single matrix.
/// </summary>
/// <param name="descriptors">Descriptors to concatenate.</param>
/// <returns>Concatenated matrix.</returns>
public Matrix<float> ConcatDescriptors(IList<Matrix<float>> descriptors)
{
int cols = descriptors[0].Cols;
int rows = descriptors.Sum(a => a.Rows);
float[,] concatedDescs = new float[rows, cols];
int offset = 0;
foreach (var descriptor in descriptors)
{
// append new descriptors
Buffer.BlockCopy(descriptor.ManagedArray, 0, concatedDescs, offset, sizeof(float) * descriptor.ManagedArray.Length);
offset += sizeof(float) * descriptor.ManagedArray.Length;
}
return new Matrix<float>(concatedDescs);
}
public class IndecesMapping
{
public int IndexStart { get; set; }
public int IndexEnd { get; set; }
public int Similarity { get; set; }
public string fileName { get; set; }
}
private const double surfHessianThresh = 300;
private const bool surfExtendedFlag = true;
private SURFDetector detector = new SURFDetector(surfHessianThresh, surfExtendedFlag);