Совмещение двух изображений с помощью ручной гомографии

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

Результаты гомографии:

[[ 7.43200521e-01 -1.79170744e-02 -1.76782990e+02]
 [ 1.00046389e-02  7.84106136e-01 -3.22549155e+01]
 [ 5.10695284e-05 -8.48641135e-05  1.00000000e+00]]

Точки, выбранные вручную: RGB:

[[ 277  708]
 [1108  654]
 [ 632  545]
 [ 922  439]
 [ 874  403]
 [ 398  376]
 [ 409  645]
 [ 445  593]
 [ 693  342]
 [ 739  244]
 [ 505  234]
 [ 408  275]
 [ 915  162]
 [1094  126]
 [ 483  115]
 [ 951  366]
 [ 517  355]]

Термальный:

[[  8 549]
 [634 491]
 [282 397]
 [496 318]
 [461 289]
 [113 269]
 [122 479]
 [148 438]
 [325 236]
 [360 162]
 [194 156]
 [121 188]
 [484 106]
 [621  67]
 [178  62]
 [515 261]
 [203 253]]
    def manual_calibration(self, rgb: cv2.UMat, thermal: cv2.UMat) -> Tuple[cv2.UMat, Tuple[int, int, int, int]]:
               
        rgb_gray = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY) 
        thermal_gray = cv2.cvtColor(thermal, cv2.COLOR_BGR2GRAY) 
        
        h_rgb, w_rgb = rgb_gray.shape
        h_th, w_th = thermal_gray.shape
        
        thermal_gray = cv2.copyMakeBorder(thermal_gray, 0, h_rgb - h_th, 0, 0, cv2.BORDER_CONSTANT, value=[0, 0, 0])
        
        merged = cv2.hconcat((rgb_gray, thermal_gray))
        
        self.merged = cv2.cvtColor(merged, cv2.COLOR_GRAY2RGB)
        
        def point_validation(ix, iy):
            if ix > w_rgb:
                ix -= w_rgb
            return ix, iy

        self.points_left = np.array([])
        self.points_right = np.array([])
        self.label = True

        def select_point(event, x, y, flags, param):
            if event == cv2.EVENT_LBUTTONDOWN: # captures left button double-click
                ix, iy = x, y
                cv2.circle(img=self.merged, center=(x,y), radius=5, color=(0,255,0),thickness=-1)
                
                ix, iy = point_validation(ix, iy)
                
                pt = np.array([ix, iy])
                
                if self.label:
                    # self.points_left = np.vstack((self.points_left, pt))
                    self.points_left = np.vstack((self.points_left, pt)) if self.points_left.size else pt
                    self.label = False
                else:
                    # self.points_right = np.vstack((self.points_right, pt))
                    self.points_right = np.vstack((self.points_right, pt)) if self.points_right.size else pt
                    self.label = True
                    
                    
                print(ix, iy)
            
    
        cv2.namedWindow('calibration')
        cv2.setMouseCallback('calibration', select_point)
        
        while True:
            cv2.imshow("calibration", self.merged)
            if cv2.waitKey(20) & 0xFF == 27:
                break
        cv2.destroyAllWindows()
        
        print(self.points_left)
        print(self.points_right)
        
        ### EDIT NEW POINT VALIDATION
        rgb_gray_check = rgb_gray
        thermal_gray_check = thermal_gray
        
        for point in self.points_left:
            cv2.circle(img=rgb_gray_check, center=point, radius=5, color=(0,255,0),thickness=-1)
            
        for point in self.points_right:
            cv2.circle(img=thermal_gray_check, center=point, radius=5, color=(0,255,0),thickness=-1)
        
        cv2.imshow('rgb', rgb_gray_check)
        cv2.imshow('thermal', thermal_gray_check)
        cv2.waitKey(0)
       
        ### EDIT NEW POINT VALIDATION


        
        
        # Compute homography

        # 0 - a regular method using all the points
        # CV_RANSAC - RANSAC-based robust method
        # CV_LMEDS - Least-Median robust method
        matrix, mask = cv2.findHomography(self.points_left, self.points_right, 0)
        
        print(matrix)
                   
        # matrix[0][3] += (w_th/2)
        # matrix[1][3] += (h_th/2)
        
        warp_src = cv2.warpPerspective(thermal, matrix, (rgb.shape[1], rgb.shape[0]))
                
        alpha = 0.5
        beta = (1.0 - alpha)
        dst_warp_blended = cv2.addWeighted(rgb, alpha, warp_src, beta, 0.0)
        
        cv2.imshow('Blended destination and warped image', dst_warp_blended)
        cv2.waitKey(0)

Исходные изображения:

Мой результат:

Можете ли вы попробовать использовать только 4 соответствия? Если они не идеально выравниваются после деформации, что-то в вашем коде не так. Если деформация подходит для этих 4 точек, скорее всего, что-то не так с некоторыми из ваших точек или с общей настройкой (деформация перспективы не может решить все виды преобразований изображения в изображение, такие как искажение объектива или произвольное движение сенсора).

Micka 23.12.2022 00:00

@Micka Я пробовал четыре и даже больше. Кажется, это никогда не работает. Я подозреваю, что это связано с разными разрешениями, но я чувствую, что гомография должна решить эту проблему. Так что я думаю, что это из-за кода... но я понятия не имею, что это такое

Blank 23.12.2022 00:07

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

Micka 23.12.2022 01:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5
3
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Так я понял это!

Я случайно перевернул параметры в функции findHomography. Так и должно быть

matrix, mask = cv2.findHomography(self.points_right, self.points_left, 0)

И, конечно же, удалите смещение для матрицы гомографии.

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

thesonyman101 23.12.2022 00:42

Другие вопросы по теме