DennerV 0 Жалоба Опубликовано April 26, 2017 Добрый день! Стоит задача в сравнении изображения с камеры с эталонным изображением. На данный момент реализован поиск объекта и поворот изображения. Сравнение пытался сделать через AbsDiff, проблема в том, что из-за качества картинки изображения получаются не пиксель в пиксель, а с небольшим смещением и/или поворотом в 1-2 градуса. Придумал что можно использовать SURF. Найти общие ключевые точки и при из помощи более точно позиционировать (если нудно масштабировать) изображения. Нашел пример использования SURF. Подскажите как получить отдельно общие точки? Может есть более лучший способ сравнения 2 изображений, чтоб получить их отличия? Пример изобрадения Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 26, 2017 SURF - да, подойдёт. См. пример из OpenCV. Можно и способ побыстрее, например того же cv::matchTemplate должно хватить. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 26, 2017 Спасибо, буду разбирать пример 10 минут назад, Nuzhny сказал: Можно и способ побыстрее, например того же cv::matchTemplate должно хватить. Не подойдет, я потому-что заранее не известно что искать, Т.е. задача заключается в сравнении 2-х плат в показать расхождения (отсутствующий или лишний элемент), например показать синий кусок пластика на фото Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 26, 2017 Если всё как на картинках выше, то совпадение всё равно найдётся. А так да, с точками надёжней. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
2expres 7 Жалоба Опубликовано April 26, 2017 1 час назад, DennerV сказал: одойдет, я потому-что заранее не известно что искать, Т.е. задача заключается в сравнении 2-х плат в показать расхождения (отсутствующий или лишний элемент), например показать синий кусок пластика на фото При обработке приведенных Вами изображений я вижу следующие проблемы: 1. Это освещение. Оно должно быть мягким, равномерным и не давать бликов. 2. Как правило элементы на разных платах установлены по разному, могут быть смещения, резисторы, конденсаторы, транзисторы, диоды могут быть под небольшими углами (что допускается по ГОСТу). Как вы планируете это учитывать? Я пытался решить вопрос с контролем качества печатных плат (целостность дорожек). Теоретически все получается, но столкнулся с проблемой освещения. Не удалось создать равномерное освещение. Сравнение проводил путем сегментации изображения и сравнения количества и площади сегментов. Если сегментов больше, то обрыв дорожки. Если меньше "закоротка". Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 26, 2017 39 минут назад, 2expres сказал: При обработке приведенных Вами изображений я вижу следующие проблемы: 1. Это освещение. Оно должно быть мягким, равномерным и не давать бликов. 2. Как правило элементы на разных платах установлены по разному, могут быть смещения, резисторы, конденсаторы, транзисторы, диоды могут быть под небольшими углами (что допускается по ГОСТу). Как вы планируете это учитывать? Я пытался решить вопрос с контролем качества печатных плат (целостность дорожек). Теоретически все получается, но столкнулся с проблемой освещения. Не удалось создать равномерное освещение. Сравнение проводил путем сегментации изображения и сравнения количества и площади сегментов. Если сегментов больше, то обрыв дорожки. Если меньше "закоротка". Скажем так, у меня скорее лабораторный образец, а не промышленная установка, поэтому с освещением худо-бедно можно решить. Как вариант расстраиваю бестеневую лампу/линзу с кольцевой подсветкой, линзу выкинуть, на ее место поставить камеру. Пока не опробовал, использую окно и белые листы бумаги) Насчет смещений я тоже думал об этом, самый простой вариант найти разность изображений (AbsDiff) а после найти контуры. Слишком маленькие контуры отсеивать, мелкие (небольшие смещения) уйдут, крупные (элементы/пустые места), останутся, тут уж придется действовать методом тыка. На данный момент проблема с точным позиционированием полученного изображения относительно контрольного Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 27, 2017 Подскажите как происходит сопоставление найденных точек? В примере drawMatches и все. Мне же нужно взять несколько общих точек на обоих изображениях, знать их координаты, чтоб можно было оценить положение, разнице в размере. Откуда берется дистанция между точками? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано April 27, 2017 У каждой точки есть дескриптор и точки сравниваются по дескрипторам, обычно L2 norm. Положение точки хранится в KeyPoint, а вот получить 'окрестность' точки, на сколько я понимаю, не тривиально, хотя это наверно зависит от метода подсчёта дескриптора. Например в FAST окрестность вроде фиксированная, но все равно наверно ищется на нескольких скейлах. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 27, 2017 Как это можно сделать (сопоставление) самому? Допустим есть modelDescriptors - 50 точек и observedDescriptors 100 - точек, общие - пусть будет 20 точек. Каким образом пробежаться по modelDescriptors и найти/не найти точкам пару в observedDescriptors . Например: modelDescriptors [0] - пара не найдена modelDescriptors [1], координаты (25, 37) - пара observedDescriptors[8], координаты (183, 347) modelDescriptors [2], координаты (75, 81) - пара observedDescriptors[14], координаты (7, 34) modelDescriptors [3] - пара не найдена что-то в этом духе Как связаны modelKeyPoints и modelDescriptors? Порядковыми номерами или есть какие-то внутренние идентификаторы? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 27, 2017 А неизвестно, какие точки каким соответствуют - это проблема. Один из способов решения - алгоритм RANSAC. Ещё один - итеративное приближение перспективного преобразования (или гомографии) методом наименьших квадратов. В примере всем этим занимается функция findHomography, которая из правильных и неправильных соответствий находи матрицу преобразования. Эти алгоритмы тоже не всесильны и могут ошибиться, но не в твоём случае с платами. И уже после того, как отработала findHomography и найдено преобразование ты можешь найти точные соответствия между наборами точек. А именно: умножаешь каждую точку из первого набора на матрицу гомографии, получаешь координаты точки на втором изображении и ищешь точное соответствие из второго набора. Только так. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 28, 2017 После findHomography получил Mat 3x3? немного не понятно как координату умножить на матрицу, т.е. М1(1, 2) * М2(3, 3). Размеры же не совпадают, или нужно еще какие-то преобразования произвести? Я тут подумал, может не обязательно сопоставлять все точки, а можно найти матрицу гомографии и по ней сразу трансформировать все изображение? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 28, 2017 Надо к координатам добавить 1 и получится вектор 3х1. Это называется однородные координаты. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 28, 2017 var srcPoints = modelKeyPoints.ToArray().Select(x => x.Point).ToList().GetRange(0, Math.Min(modelKeyPoints.Size, observedKeyPoints.Size)).ToArray(); var destPoints = observedKeyPoints.ToArray().Select(x => x.Point).ToList().GetRange(0, Math.Min(modelKeyPoints.Size, observedKeyPoints.Size)).ToArray(); Mat hom = new Mat(); CvInvoke.FindHomography(srcPoints, destPoints, hom, HomographyMethod.Ransac, 5); var arr = hom.GetData(); var b = new double[,] { {BitConverter.ToDouble(arr, 0), BitConverter.ToDouble(arr, 8), BitConverter.ToDouble(arr, 16)}, {BitConverter.ToDouble(arr, 24), BitConverter.ToDouble(arr, 32), BitConverter.ToDouble(arr, 40)}, {BitConverter.ToDouble(arr, 48), BitConverter.ToDouble(arr, 56), BitConverter.ToDouble(arr, 64)} }; for (var i = 0; i < matches.Size; i++) { var match = matches[i].ToArray(); if (mask.GetData(i)[0] == 0) continue; foreach (var e in match) { var a = new double[] {modelKeyPoints[e.QueryIdx].Point.X, modelKeyPoints[e.QueryIdx].Point.Y, 1.0}; var c = multiplication(a, b); MessageBox.Show(string.Format("Point: {0}", c)); } } массив b после перевода из байт в дубл содержит отрицательные числа, что мне кажется неправильным. Или я не так перевел? Какой порядок координат должен быть? (x, y, z)? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 28, 2017 1. Отрицательные конечно могут быть: там же смещения и углы поворота есть. Можно же поворачивать в разные стороны и сдвигаться в разные стороны. 2. (x, y, 1). Откуда на плоскости z? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 28, 2017 3 минуты назад, Nuzhny сказал: 1. Отрицательные конечно могут быть: там же смещения и углы поворота есть. Можно же поворачивать в разные стороны и сдвигаться в разные стороны. 2. (x, y, 1). Откуда на плоскости z? под z я имел ввиду 1 когда умножаю координаты на матрице то получаю отрицательные координаты, а такого уже быть не может Может неправильно что-то перевожу или порядок спутал Умножение: return new[] {a[0]*b[0, 0] + a[1]*b[1, 0] + a[2]*b[2, 0], a[0]*b[0, 1] + a[1]*b[1, 1] + a[2]*b[2, 1], a[0]*b[0, 2] + a[1]*b[1, 2] + a[2]*b[2, 2]} Получение b, написал выше, тип должен быть дубл? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 28, 2017 Код на С# выглядит довольно страшно и громоздко. Умножать как обычно: строка на столбец, всё как в школе учили. Отрицательные значения координат появиться могут: допустим, плата смещена на втором изображении сильно влево, выходит за границы. Конечно, координаты будут отрицательными. А нельзя написать пример на С++, убедиться, что он работает, а только потом переписывать? Потому что проблемы с типами (double или float) быть могут, почему нет? В С++ проблем с этим нет, потому что всё решается на этапе компиляции. А твои конверты типа BitConverter.ToDouble(arr, 0) могут привести к чему угодно, если ты с типом не угадал. P.S. В очередной раз убеждаюсь, что лучше всего писать такого рода приложения на С++ или Питоне, в крайнем случае на Матлабе. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано April 28, 2017 В моем случае отрицательных координат быть не должно, во всяком случае больших маленьких чисел, потому-что картинки почти одинаковые. findHomography возвращает Мат типа double, это не я придумал На выходных подумаю/почитаю, может что в голову да и придет Спасибо Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DennerV 0 Жалоба Опубликовано May 11, 2017 С гомографиейй так до конца и не разобрался Прочел здесь http://stackoverflow.com/questions/28725273/opencv-drawmatches-error, что matches содержит сопоставление между точками matches[0].TrainIdx и matches[0].QueryIdx, так ли это? Правильно ли я понял? Посчитал длины отрезков соседних точек - вроде как сходится, по координатам тоже похоже. Подскажите, как используя имеющеюся координаты повернуть второе изображение так, чтоб точки встали по координатам точек первого изображения? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано May 11, 2017 cv::warpPerspective P.S. Я люблю читать исходники библиотек, которые использую. Можно делать это и в отладчике. После этого большинство вопросов проясняется. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах