Как использовать библиотеку Surgu Emgu CV, чтобы соответствовать библиотеке изображений - PullRequest
1 голос
/ 12 февраля 2011

Набор примеров Emgu CV содержит пример того, как использовать SURFDetector для обнаружения объектов из функции, а затем использовать вызов MatchFeature Feature2DTracker (который, кажется, использует KNN), чтобы сопоставить изображение «модели» с «наблюдаемым» изображением.Эта часть имеет смысл.

Теперь, если я хочу создать библиотеку изображений, каждое из которых использует функции SURF изображения, чтобы найти лучшее соответствие для данного изображения, каковы мои варианты?Могу ли я построить дерево вместо того, чтобы выполнять сопоставление методом грубой силы с каждым изображением в моей библиотеке?Я запутался, потому что Эмгу, кажется, строит какое-то дерево, но только между двумя изображениями:

     //Create a SURF Tracker using k-d Tree
     SURFTracker tracker = new SURFTracker(modelFeatures);

Я прочитал почти все темы на сайте по этой теме, но не могу понять, как это сделать.начать.Я также подумал об использовании сопоставления гистограмм - разбиении каждого канала RGB на бины и сравнении нормализованного числа.Вместо того, чтобы вычислять евклидово расстояние до каждого изображения в библиотеке, если бы я хотел разделить свое пространство поиска на основе количества RGB, это все равно означало бы разветвление на одном из R, G, B - и я не уверен, как построитьэто дерево решений.

Я только начал читать об этой теме несколько дней назад, поэтому извиняюсь за свою наивность.

Ответы [ 3 ]

1 голос
/ 06 марта 2011

SURFTracker, кажется, использует библиотеку FLANN (Быстрая библиотека для приблизительных ближайших соседей), которая поставляется с OpenCV (как и привязки Emgu, также), пока она:

  • строит дерево из дескрипторов, извлеченных из изображения шаблона (чтобы быстрее сопоставить точки образца с точками шаблона). Таким образом, дерево построено только для одного изображения (шаблон).
  • когда передается образец, он извлекает дескрипторы, вычисляет совпадение (спаривание между шаблоном и дескрипторами изображения), учитывая также пространственную согласованность точек сопоставления (справа налево, слева направо левая сторона)

Предположим, что вы хотите быть быстрее, чем просто выполнять описанную выше процедуру для каждого изображения, вам нужно будет построить одно дерево из каждого дескриптора для каждого изображения и поместить его в индекс FLANN, пока отслеживание того, какой дескриптор пришел с какого изображения (возможно, в отдельном массиве).

Получив изображение, вы можете извлечь из него все дескрипторы и сопоставить их одно за другим с деревом FLANN (это быстрее, чем делать это с другим деревом для каждой коллекции дескрипторов шаблона). Таким образом, для каждого дескриптора X в образце вы получаете наиболее похожий дескриптор Y, полученный из изображения Z. Они могут использоваться в качестве голосов для похожих изображений (см. http://en.wikipedia.org/wiki/Bag_of_words_model).

Однако этот метод не учитывает пространственную согласованность точек ... но можно проверить, что и для верхних k изображений, за которые мы имеем голоса (k << N, число всех изображения в системе). </p>

1 голос
/ 28 апреля 2015

Этот код создает матрицу каждого изображения, добавляет их все вместе, затем получает, создает индекс 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);
1 голос
/ 12 февраля 2011

Вы можете посмотреть TrafficSignRecognition CV EMGU. Это так же, как пример SURFFeature, но применяется в реальной жизни. Он может определить, соответствует ли данное изображение данному изображению и сколько их существует. Я попробовал это. Вы можете взглянуть на это.

...