Вопрос

У меня есть набор изображений, и я хочу провести перекрестное сопоставление между всеми и отобразить результаты с помощью трекбаров, используя OpenCV 2.4.6 (пакет ROS Hydro).Сопоставляющая часть выполняется с использованием вектора векторов векторов cv::DMatch-объектов:

image[0] --- image[3] -------- image[8] ------ ...
   |             |                 |
   |         cv::DMatch-vect   cv::DMatch-vect
   |
image[1] --- ...
   |
image[2] --- ...
   |
  ...
   |
image[N] --- ...

Поскольку мы опускаем сопоставление изображения с самим собой (нет смысла делать это) и поскольку изображение запроса может не совпадать со всеми остальными, каждый набор сопоставленных изображений поездов для изображения запроса может иметь размер, отличный от остальных.Обратите внимание, что при правильной реализации я фактически сопоставляю пару изображений дважды, что, конечно, не является оптимальным (тем более, что я использовал средство сопоставления методом грубой силы с включенной перекрестной проверкой, что в основном означает, что я сопоставляю пару изображений 4 раза!) но на данный момент это все.Чтобы избежать отрисовки совпадающих пар изображений "на лету", я заполнил вектор векторов cv::Mat-объектов.Каждый cv::Mat представляет текущее изображение запроса и некоторые подобранный изображение поезда (я заполняю его с помощью cv::drawMatches()):

image[0] --- cv::Mat[0,3] ---- cv::Mat[0,8] ---- ...
   |
image[1] --- ...
   |
image[2] --- ...
   |
  ...
   |
image[N] --- ...

Примечание:В приведенном выше примере cv::Mat[0,3] означает cv::Mat, который хранит произведение cv::drawMatches() с использованием image[0] и image[3].

Вот настройки графического интерфейса:

  • Главное окно:здесь я показываю текущее изображение запроса.Используя панель отслеживания - назовем ее TRACK_QUERY - я перебираю каждое изображение в моем наборе.
  • Вторичное окно:здесь я показываю подобранную пару (запрос, поезд), где комбинация положения ползунка TRACK_QUERY и положения ползунка другой панели треков в этом окне - назовем это TRACK_TRAIN - позволяет мне перебирать все cv ::Mat-match-images для текущего изображения запроса.

Проблема здесь связана с тем фактом, что каждый запрос может содержать переменное количество совпадающих изображений поездов.Мой TRACK_TRAIN должен иметь возможность настраивать количество совпадающих изображений поездов, то есть количество элементов в каждом cv ::Mat-векторе для текущего изображения запроса.К сожалению, до сих пор я не смог найти способ сделать это.Cv::createTrackbar() требует параметра count, который, насколько я вижу, устанавливает предел ползунка трекбара и не могу будут изменены позже.Пожалуйста, поправьте меня, если я ошибаюсь, поскольку это именно то, что меня беспокоит.Возможное решение (менее элегантное и включающее различные проверки, чтобы избежать ошибок вне диапазона) состоит в том, чтобы взять размер наибольшего набора совпадающих изображений поездов и использовать его в качестве предела для my TRACK_TRAIN.Я бы хотел избежать этого, если это возможно.Другое возможное решение включает в себя создание трекбара для каждого изображения запроса с соответствующим диапазоном значений и замену каждого из них в моих дополнительных окнах в соответствии с выбранным изображением запроса.На данный момент это кажется более простым способом, но создает большие накладные расходы на трекбары, не говоря уже о том факте, что я не слышал об OpenCV, позволяющем скрывать элементы управления GUI.Вот два примера, которые могли бы немного прояснить ситуацию:

Пример 1: В главном окне я выбираю изображение 2 с помощью TRACK_QUERY.Для этого изображения мне удалось сопоставить 5 других изображений из моего набора.Допустим, это изображения 4, 10, 17, 18 и 20.Дополнительное окно обновляется автоматически и показывает мне соответствие между изображениями 2 и 4 (первое в подмножестве совпадающих изображений поездов).TRACK_TRAIN должен переключаться с 0 на 4.Перемещение ползунка в обоих направлениях позволяет мне просматривать изображения 4, 10, 17, 18 и 20, обновляя каждый раз дополнительное окно.

Пример 2: В главном окне я выбираю изображение 7 с помощью TRACK_QUERY.Для этого изображения мне удалось сопоставить 3 других изображения из моего набора.Допустим, это изображения 0, 1, 11 и 19.Дополнительное окно обновляется автоматически и показывает мне соответствие между изображением 2 и изображением 0 (первое в подмножестве совпадающих изображений поездов).TRACK_TRAIN должен перейти от 0 к 2.Перемещение ползунка в обоих направлениях позволяет мне просматривать изображения 0, 1, 1 и 19, обновляя каждый раз дополнительное окно.

Если у вас есть какие-либо вопросы, не стесняйтесь задавать, и я постараюсь ответить на них как можно лучше.Заранее спасибо!

PS:К сожалению, в том виде, в каком представлен пакет ROS, он имеет самый минимум того, что может предложить OpenCV.Никакой интеграции с Qt, никакого OpenMP, никакого OpenGL и т.д.

Это было полезно?

Решение

Проведя еще несколько исследований, я почти уверен, что в настоящее время это невозможно.Вот почему я реализовал первое предложение, которое я привел в своем вопросе - используйте вектор совпадений с наибольшим количеством совпадений в нем, чтобы определить максимальный размер трекбара, а затем используйте некоторую проверку, чтобы избежать исключений вне диапазона.Ниже есть более или менее подробное описание того, как все это работает.Поскольку процедура сопоставления в моем коде включает в себя некоторые дополнительные проверки, которые не касаются рассматриваемой проблемы, я пропущу ее здесь.Обратите внимание, что в данном наборе изображений, которые мы хотим сопоставить, я ссылаюсь на изображение как object-image, когда это изображение (пример:карточка) в данный момент сопоставлена с изображением сцены (пример:набор карточек) - верхний уровень вектора совпадений (см. Ниже) и равен индексу в обработанных изображениях (см. Ниже).Я нахожу обозначение train / query в OpenCV несколько сбивающим с толку.Эта нотация сцены / объекта взята из http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html.Вы можете изменить или поменять местами обозначения по своему вкусу, но убедитесь, что вы меняете их везде соответствующим образом, иначе вы можете получить несколько странных результатов.

// stores all the images that we want to cross-match
std::vector<cv::Mat> processedImages;
// stores keypoints for each image in processedImages
std::vector<std::vector<cv::Keypoint> > keypoints;
// stores descriptors for each image in processedImages 
std::vector<cv::Mat> descriptors;

// fill processedImages here (read images from files, convert to grayscale, undistort, resize etc.), extract keypoints, compute descriptors
// ...

// I use brute force matching since I also used ORB, which has binary descriptors and HAMMING_NORM is the way to go
cv::BFmatcher matcher;
// matches contains the match-vectors for each image matched to all other images in our set
// top level index matches.at(X) is equal to the image index in processedImages
// middle level index matches.at(X).at(Y) gives the match-vector for the Xth image and some other Yth from the set that is successfully matched to X
std::vector<std::vector<std::vector<cv::DMatch> > > matches;
// contains images that store visually all matched pairs
std::vector<std::vector<cv::Mat> > matchesDraw;

// fill all the vectors above with data here, don't forget about matchesDraw
// stores the highest count of matches for all pairs - I used simple exclusion by simply comparing the size() of the current std::vector<cv::DMatch> vector with the previous value of this variable
long int sceneWithMaxMatches = 0;
// ...

// after all is ready do some additional checking here in order to make sure the data is usable in our GUI. A trackbar for example requires AT LEAST 2 for its range since a range (0;0) doesn't make any sense
if(sceneWithMaxMatches < 2)
  return -1;

// in this window show the image gallery (scene-images); the user can scroll through all image using a trackbar
cv::namedWindow("Images", CV_GUI_EXPANDED | CV_WINDOW_AUTOSIZE);
// just a dummy to store the state of the trackbar 
int imagesTrackbarState = 0;
// create the first trackbar that the user uses to scroll through the scene-images
// IMPORTANT: use processedImages.size() - 1 since indexing in vectors is the same as in arrays - it starts from 0 and not reducing it by 1 will throw an out-of-range exception
cv::createTrackbar("Images:", "Images", &imagesTrackbarState, processedImages.size() - 1, on_imagesTrackbarCallback, NULL);
// in this window we show the matched object-images relative to the selected image in the "Images" window
cv::namedWindow("Matches for current image", CV_WINDOW_AUTOSIZE);
// yet another dummy to store the state of the trackbar in this new window
int imageMatchesTrackbarState = 0;
// IMPORTANT: again since sceneWithMaxMatches stores the SIZE of a vector we need to reduce it by 1 in order to be able to use it for the indexing later on
cv::createTrackbar("Matches:", "Matches for current image", &imageMatchesTrackbarState, sceneWithMaxMatches - 1, on_imageMatchesTrackbarCallback, NULL);

while(true)
{
  char key = cv::waitKey(20);
  if(key == 27)
    break;

  // from here on the magic begins
  // show the image gallery; use the position of the "Images:" trackbar to call the image at that position
  cv::imshow("Images", processedImages.at(cv::getTrackbarPos("Images:", "Images")));

  // store the index of the current scene-image by calling the position of the trackbar in the "Images:" window
  int currentSceneIndex = cv::getTrackbarPos("Images:", "Images");
  // we have to make sure that the match of the currently selected scene-image actually has something in it
  if(matches.at(currentSceneIndex).size())
  {
    // store the index of the current object-image that we have matched to the current scene-image in the "Images:" window
    int currentObjectIndex = cv::getTrackbarPos("Matches:", "Matches for current image");
    cv::imshow(
            "Matches for current image",
            matchesDraw.at(currentSceneIndex).at(currentObjectIndex < matchesDraw.at(currentSceneIndex).size() ? // is the current object index within the range of the matches for the current object and current scene
            currentObjectIndex : // yes, return the correct index
            matchesDraw.at(currentSceneIndex).size() - 1));  // if outside the range show the last matched pair!
  }
}

// do something else
// ...

Сложная часть - это панель отслеживания во втором окне, отвечающая за доступ к соответствующим изображениям к нашему текущему выбранному изображению в окне "Изображения".Как я объяснял выше, я установил для трековой панели "Совпадения:" в окне "Совпадения для текущего изображения" значение от 0 до (sceneWithMaxMatches-1).Однако не все изображения имеют одинаковое количество совпадений с остальными в наборе изображений (применяется в десятикратном размере, если вы выполнили дополнительную фильтрацию для обеспечения надежных совпадений, например, используя свойства гомографии, теста соотношения, проверки минимального / максимального расстояния и т.д.).Поскольку я не смог найти способ динамической настройки диапазона трекбара, мне понадобилась проверка индекса.В противном случае для некоторых изображений и их совпадений приложение выдаст исключение вне диапазона.Это связано с простым фактом, что для некоторых совпадений мы пытаемся получить доступ к вектору совпадений с индексом, большим, чем его размер минус 1, потому что cv::getTrackbarPos() проходит весь путь до (sceneWithMaxMatches - 1).Если позиция трекбара выходит за пределы диапазона для выбранного в данный момент вектора с совпадениями, я просто устанавливаю matchDraw-image в "Соответствует текущему изображению" на самое последнее значение в векторе.Здесь я использую тот факт, что индексация не может опускаться ниже нуля, а также положение трекбара, поэтому проверять нужно не это, а только то, что идет после начальной позиции 0.Если это не ваш случай, убедитесь, что вы проверили и нижнюю границу, а не только верхнюю.

Надеюсь, это поможет!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top