Мне удалось добиться хорошего результата. Я немного переписал твой код, вот измененная часть:
def generateTransformation(allMatches, keypointsA, keypointsB, ratio):
if not allMatches:
return None
matches = []
for match in allMatches:
# Lowe's ratio test
if len(match) == 2 and (match[0].distance / match[1].distance) < ratio:
matches.append(match[0])
pointsA = numpy.float32([keypointsA[m.queryIdx] for m in matches])
pointsB = numpy.float32([keypointsB[m.trainIdx] for m in matches])
if len(pointsA) > 2:
transformation = cv2.estimateRigidTransform(pointsA, pointsB, True)
if transformation is None or transformation.shape[1] < 1 or transformation.shape[0] < 1:
return None
return transformation
else:
return None
paths = glob.glob("a*.jpg")
images = readImages(paths[::-1])
result = images[0]
while len(images) > 1:
imgR = images.pop()
imgL = images.pop()
interestsR, featuresR = findAndDescribeFeatures(imgR)
interestsL, featuresL = findAndDescribeFeatures(imgL)
allMatches = matchFeatures(featuresR, featuresL)
transformation = generateTransformation(allMatches, interestsR, interestsL, 0.75)
if transformation is None or transformation[0, 2] < 0:
images.append(imgR)
continue
transformation[0, 0] = 1
transformation[1, 1] = 1
transformation[0, 1] = 0
transformation[1, 0] = 0
transformation[1, 2] = 0
result = cv2.warpAffine(imgR, transformation, (imgR.shape[1] +
int(transformation[0, 2] + 1), imgR.shape[0]))
result[:, :imgL.shape[1]] = imgL
cv2.imshow("R", result)
images.append(result)
cv2.waitKey(1)
cv2.imshow("Result", result)
Итак, ключевая вещь, которую я изменил, - это трансформация изображений. Я использую estimateRigidTransform()
вместо findHomography()
для вычисления преобразования изображения. Из этой матрицы преобразования я извлекаю только перевод координат x , который находится в ячейке [0, 2]
полученной матрицы Affine Transformation transformation
. Я установил другие элементы матрицы преобразования, как если бы это было преобразование идентичности (без масштабирования, без перспективы, без поворота или перевода y ). Затем я передаю его на warpAffine()
для преобразования imgR
так же, как вы сделали с warpPerspective()
.
Вы можете сделать это, потому что у вас есть стабильные положения камеры и вращающегося объекта, и вы снимаете с прямым видом объекта спереди. Это означает, что вам не нужно вносить какие-либо поправки в перспективное / масштабирующее / поворотное изображение и вы можете просто «склеить» их вместе по оси x .
Я думаю, что ваш подход неудачен, потому что вы на самом деле наблюдаете за бутылкой со слегка наклоненным обзором камеры, или бутылка не находится в середине экрана. Я постараюсь описать это с изображением. Я изображаю какой-то текст на бутылке красным цветом. Например, алгоритм находит пару совпадающих точек (зеленого цвета) в нижней части захваченного круглого объекта. Обратите внимание, что точка движется не только вправо, но и по диагонали вверх. Затем программа рассчитывает преобразование с учетом точек, которые немного смещаются вверх. Это продолжает ухудшаться кадр за кадром.
Распознавание совпадающих точек изображения также может быть немного неточным, поэтому извлечение только перевода x еще лучше, потому что вы даете алгоритму «подсказку», какая у вас реальная ситуация. Это делает его менее применимым для других условий, но в вашем случае это значительно улучшает результат.
Также я отфильтровываю некоторые неправильные результаты с проверкой if transformation[0, 2] < 0
(она может вращаться только в одном направлении, и код не будет работать, если он в любом случае отрицателен).