Регистрация изображений с использованием Python и взаимной корреляции - PullRequest
10 голосов
/ 10 февраля 2012

Я получил два изображения, показывающие абсолютно одинаковое содержание: пятна в 2D-гауссовой форме.Я называю эти два 16-битных png-файла «left.png» и «right.png».Но так как они получены с помощью немного другой оптической системы, соответствующие пятна (физически одинаковые) появляются в немного разных позициях.Значение вправо слегка растянуто, искажено или около того нелинейным образом.Поэтому я хотел бы получить преобразование слева направо.

Так что для каждого пикселя на левой стороне с его координатами x и y мне нужна функция, дающая мне компоненты вектора смещения, который указываетк соответствующему пикселю с правой стороны.

В предыдущем подходе я пытался получить положения соответствующих пятен, чтобы получить относительные расстояния deltaX и deltaY.Затем эти расстояния я подгонял к расширению Тейлора до второго порядка T (x, y), давая мне x- и y-компоненту вектора смещения для каждого пикселя (x, y) слева, указывая на соответствующий пиксель(x ', y') справа.

Чтобы получить более общий результат, я хотел бы использовать нормализованную взаимную корреляцию.Для этого я умножаю каждое пиксельное значение слева на соответствующее пиксельное значение справа и суммирую по этим продуктам.Преобразование, которое я ищу, должно соединить пиксели, которые максимизируют сумму.Поэтому, когда сумма максимальна, я знаю, что я умножил соответствующие пиксели.

Я действительно много пытался с этим, но не смог.Мой вопрос: есть ли у кого-нибудь из вас идея или когда-либо подобное.

import numpy as np
import Image

left = np.array(Image.open('left.png'))
right = np.array(Image.open('right.png'))

# for normalization (http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation)    
left = (left - left.mean()) / left.std()
right = (right - right.mean()) / right.std()

Пожалуйста, дайте мне знать, если я смогу прояснить этот вопрос.Мне все еще нужно проверить, как отправлять вопросы с использованием латекса.

Большое спасибо за ввод.

left right

[left.png] http://i.stack.imgur.com/oSTER.png [right.png] http://i.stack.imgur.com/Njahj.png

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

ОБНОВЛЕНИЕ 1

Я пытаюсь прояснить свой вопрос. Я ищу векторное поле с векторами смещения, которые указывают от каждого пикселя в left.png ксоответствующий пиксель в right.png . Моя проблема в том, что я не уверен насчет имеющихся у меня ограничений.

enter image description here

где vector r (компоненты x и y) указывают на пиксель в left.png, а вектор r-prime (компоненты x-prime и y-prime) указывает на соответствующий пиксель в right.png. для каждого r существует вектор смещения.

То, что я делал ранее, было то, что я вручную нашел компоненты векторного поля d и подгонял их к полиному второй степени:

enter image description here

Итак, я установил:

enter image description here и

enter image description here

Имеет ли это для вас смысл?Можно ли получить все дельта-х (х, у) и дельта-у (х, у) с взаимной корреляцией?Кросс-корреляция должна быть максимальной, если соответствующие пиксели связаны друг с другом через векторы смещения, верно?

ОБНОВЛЕНИЕ 2

Итак, алгоритм, о котором я думал, выглядит следующим образом:

  1. Deform right.png
  2. Получить значение кросс-корреляции
  3. Deform right.png далее
  4. Получить значение кросс-корреляции и сравнить сзначение до
  5. Если оно больше, хорошая деформация, если нет, переделать деформацию и сделать что-то еще
  6. После максимизации значения взаимной корреляции, узнать, какая там деформация:)

О деформации: можно сначала сделать сдвиг в направлении x и y, чтобы максимизировать взаимную корреляцию, затем на втором шаге растянуть или сжать x- и y-зависимую и на третьем шаге деформировать квадратичные x- и yи повторить эту процедуру итеративноУ меня действительно есть проблема сделать это с целочисленными координатами.Как вы думаете, мне пришлось бы интерполировать картину, чтобы получить непрерывное распределение ??Я должен снова подумать об этом :( Спасибо всем за участие:)

Ответы [ 3 ]

2 голосов
/ 13 февраля 2012

OpenCV (и вместе с ним привязка Python Opencv) имеет класс StarDetector , который реализует этот алгоритм .

В качестве альтернативы вы можете взглянуть наКласс OpenCV SIFT , который обозначает преобразование инвариантного элемента масштаба.

Обновление

Что касается вашего комментария, я понимаю, что "правильное" преобразование будетмаксимизировать взаимную корреляцию между изображениями, но я не понимаю, как вы выбираете набор преобразований для максимизации.Возможно, если вы знаете координаты трех совпадающих точек (либо по эвристике, либо выбирая их вручную), и если вы ожидаете сходства, вы можете использовать что-то вроде cv2.getAffineTransform , чтобы получить хорошее начальное преобразование дляваш процесс максимизации.Оттуда вы можете использовать небольшие дополнительные преобразования, чтобы получить набор для максимизации.Но этот подход кажется мне как переизобретение чего-то, о чем мог бы позаботиться SIFT.

Чтобы реально преобразовать ваше тестовое изображение, вы можете использовать cv2.warpAffine , который также может позаботиться о границезначения (например, pad с 0).Для расчета взаимной корреляции вы можете использовать scipy.signal.correlate2d .

Обновление

Ваше последнее обновление действительно прояснило некоторые моменты для меня,Но я думаю, что векторное поле смещений - не самая естественная вещь для поиска, и это также то, откуда возникло недоразумение.Я размышлял больше в соответствии с глобальным преобразованием T, которое применяется к любой точке (x, y) на левом изображении, дает (x ', y') = T (x, y) направая сторона, но T имеет одинаковую аналитическую форму для каждого пикселя.Например, это может быть комбинация смещения, вращения, масштабирования, возможно, некоторого преобразования перспективы.Я не могу сказать, реалистично или нет надеяться найти такое преобразование, это зависит от вашей установки, но если сцена физически одинакова с обеих сторон, я бы сказал, что разумно ожидать некоторого аффинного преобразования.Вот почему я предложил cv2.getAffineTransform .Конечно, тривиально вычислить поле вектора смещения из такого T, поскольку это просто T (x, y) - (x, y).

Большим преимуществом будет то, что у вас очень малостепеней свободы для вашего преобразования, я бы сказал, 2N степеней свободы в векторном поле смещения, где N - число ярких пятен.

Если это действительно аффинное преобразование, я бы предложилнекоторый алгоритм, подобный следующему:

  • определить три яркие и хорошо изолированные точки слева
  • для каждого из этих трех точек, определить ограничивающий прямоугольник, чтобы вы могли надеяться определить соответствующиеПятно внутри него на правом изображении
  • найдите координаты соответствующих пятен, например, с помощью некоторого метода корреляции, как это реализовано в cv2.matchTemplate , или просто путем нахождения самого яркого пятна в ограничительной рамке.
  • когда у вас есть три совпадающие пары координат, вычислите аффинное преобразование, которое преобразует один наборt в другое с помощью cv2.getAffineTransform .
  • примените это аффинное преобразование к левому изображению, в качестве проверки, если вы нашли правильное, которое можно вычислить, если общая нормализованная взаимная корреляция равнавыше некоторого порога или значительно падает, если вы смещаете одно изображение относительно другого.
  • , если вы хотите и все еще нуждаетесь в этом, рассчитайте векторное поле смещения тривиально из вашего преобразования T.

Обновление

Кажется, cv2.getAffineTransform ожидает неуклюжий тип данных ввода 'float32'.Давайте предположим, что исходные координаты (sxi,syi) и пункт назначения (dxi,dyi) с i=0,1,2, тогда вам нужно

src = np.array( ((sx0,sy0),(sx1,sy1),(sx2,sy2)), dtype='float32' )
dst = np.array( ((dx0,dy0),(dx1,dy1),(dx2,dy2)), dtype='float32' )

result = cv2.getAffineTransform(src,dst)
1 голос
/ 14 февраля 2012

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

  1. Выполнить взаимную корреляцию для подгрупп кластеров точек.Возьмите, например, три точки в верхнем правом углу и найдите оптимальный сдвиг по оси x через взаимную корреляцию.Это дает вам грубое преобразование для верхнего левого угла.Повторите эти действия для максимально возможного количества кластеров, чтобы получить разумную карту ваших преобразований.Установите это с вашим расширением Тейлора, и вы можете быть достаточно близко.Однако, чтобы ваша взаимная корреляция работала каким-либо образом, разница в смещении между точками должна быть меньше, чем протяженность пятна, иначе вы никогда не сможете заставить все точки в кластере перекрываться одновременно с одним смещением.В этих условиях вариант 2 может быть более подходящим.

  2. Если смещения относительно малы (что я считаю условием для варианта 1), то мы могли бы предположить, что для данного местана левом изображении самое близкое пятно на правом изображении является соответствующим пятном.Таким образом, для каждого пятна на левом изображении мы находим ближайшее пятно на правом изображении и используем его в качестве смещения в этом месте.Из 40 с чем-то хорошо распределенных векторов смещений мы можем получить разумную аппроксимацию фактического смещения, подгоняя разложение Тейлора.

  3. Это, вероятно, самый медленный метод, но, возможно, самый надежныйесли у вас большие смещения (и, следовательно, вариант 2 не работает): используйте что-то вроде эволюционного алгоритма, чтобы найти смещение.Примените случайное преобразование, вычислите оставшуюся ошибку (вам может потребоваться определить ее как сумму наименьшего расстояния между точками в исходном и преобразованном изображении) и улучшите преобразование с помощью этих результатов.Если ваши смещения достаточно велики, вам может потребоваться очень широкий поиск, так как вы, вероятно, получите множество локальных минимумов в вашем ландшафте.

Я бы попробовал вариант 2, так как кажется, что ваши смещения могутбыть достаточно маленьким, чтобы легко связать пятно на левом изображении с пятном на правом изображении.

Обновление

Я предполагаю, что ваша оптика вызывает нелинейные искажения и имеет два отдельных луча (разные фильтры вкаждый?) сделает отношения между двумя изображениями еще более нелинейными.Аффинное преобразование, которое предлагает PiQuer, может дать разумный подход, но, вероятно, никогда не сможет полностью покрыть фактические искажения.

Я думаю, что ваш подход подгонки к полиному Тейлора низкого порядка - это хорошо.Это работает для всех моих приложений с похожими условиями.Высокие порядки, вероятно, должны быть такими, как xy ^ 2 и x ^ 2y;ничего выше этого вы не заметите.

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

Вариант 2 выше по-прежнему является моим предложением для получения двух изображений вперекрытия.Это может быть полностью автоматизировано, и я не уверен, что вы имеете в виду, когда хотите получить более общий результат.

Обновление 2

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

В принципе, в предложенном решении нет ничего плохого, но то, насколько оно работает или нет, сильно зависит от размера ваших деформаций и надежности алгоритма оптимизации.Если вы начинаете с очень небольшого перекрытия, тогда может быть трудно найти хорошую отправную точку для вашей оптимизации.Тем не менее, если у вас есть достаточное перекрытие для начала, тогда вы должны были бы сначала найти деформацию для каждой точки, но в комментарии вы указываете, что это не работает.

Возможно, вы можете пойти на смешаннуюРешение: найдите взаимную корреляцию кластеров точек, чтобы получить отправную точку для вашей оптимизации, а затем настройте деформацию, используя процедуру, описанную в вашем обновлении.Таким образом:

  1. Для сегмента пикселя NxN найдите сдвиг между левым и правым изображениями
  2. Повторите, скажем, для 16 из этих сегментов
  3. Вычислите приближениедеформация с использованием этих 16 точек
  4. Используйте это в качестве отправной точки вашего подхода к оптимизации
0 голосов
/ 16 мая 2013

Возможно, вы захотите взглянуть на bunwarpj , который уже делает то, что вы пытаетесь сделать.Это не Python, но я использую его именно в этом контексте.Вы можете экспортировать простое текстовое преобразование сплайна и использовать его, если хотите.

...