如何应用仿射变换结果来调整多个 ROI,而不是在 OpenCV 中变换整个图像?

问题描述 投票:0回答:1

我正在使用 OpenCV 和 AKAZE 进行图像对齐过程,我需要一些关于如何应用仿射变换的结果来在裁剪图像之前调整多个 ROI(感兴趣区域)的坐标的说明。

这是我目前正在做的事情:

我加载模板图像(黄金图像)并允许用户在其中选择 ROI。 然后,我使用 cv2.matchTemplate 在另一个图像(DUT 图像)中查找模板。 之后,我使用 AKAZE 检测关键点和描述符,并使用结果通过 cv2.estimateAffine2D 计算仿射变换矩阵。 最后,我应用仿射变换来对齐 DUT 图像并裁剪匹配区域。 我现在想要实现的是在裁剪 DUT 图像之前使用仿射变换矩阵调整多个 ROI 的坐标。本质上,我想将变换应用于 ROI,而不是变换整个图像并随后进行裁剪。

是否可以直接用仿射变换矩阵(M)调整ROI坐标,而不是变换整个图像?如果是这样,我如何将这种转换应用于每个投资回报率?我可以使用矩阵运算来更新 ROI 坐标而不转换整个图像吗?

这是我当前正在使用的相关代码:

akaze = cv2.AKAZE_create(threshold=0.0001, 
                          nOctaves=2, 
                          nOctaveLayers=2
                          )

# Detect keypoints and compute descriptors
keypoints_ref, descriptors_ref = akaze.detectAndCompute(image_ref, None)
keypoints_dut, descriptors_dut = akaze.detectAndCompute(cropped_dut, None)

# Brute force matcher to compare descriptors
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(descriptors_ref, descriptors_dut)
matches = sorted(matches, key=lambda x: x.distance)

# Estimate affine transformation
points_gold = np.array([keypoints_ref[m.queryIdx].pt for m in matches], dtype=np.float32)
points_dut = np.array([keypoints_dut[m.trainIdx].pt for m in matches], dtype=np.float32)

#Affine transformation matrix M is obtained from AKAZE keypoints matching
M, mask = cv2.estimateAffine2D(points_dut, points_gold, method=cv2.RANSAC)

# Example of applying the transformation to the DUT image
aligned_dut_color = cv2.warpAffine(cropped_dut, M, (image_ref.shape[1], image_ref.shape[0]))

# What I need is to apply the transformation to ROI coordinates
# instead of applying it to the whole cropped image.

任何有关如何将此转换应用于 ROI 坐标的帮助或建议将不胜感激!

python opencv image-processing computer-vision
1个回答
0
投票

我发现问题源于仿射变换矩阵如何 M 正在计算中。最初,我根据原始图像中裁剪的感兴趣区域 (ROI) 计算 M。但是,这种方法在将 M 应用于 ROI 坐标时会导致不一致。为了解决此问题,我使用整个原始图像中的点而不是裁剪后的 ROI 重新计算了 M。这一调整确保了转换的一致和准确应用,从而解决了该问题。以下是更新后的实施:

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Load the images
captured_image = cv2.imread('path/to/captured_image.jpg')
reference_image = cv2.imread('path/to/reference_image.jpg')
ROI = 1251, 1679, 165, 54

# Affine transformation matrix
M = np.array([[9.99039072e-01, -2.83095545e-02, 5.60160920e+00],
              [2.86278888e-02, 9.98372176e-01, 4.74288624e+01]], np.float32)

x, y, width, height = ROI
roi = np.array([[x, y], [x + width, y], [x + width, y + height], [x, y + height]], dtype=np.float32)
roi = roi.reshape((-1, 1, 2))

# Apply affine transformation to the bounding box points
roi_trans = cv2.transform(roi, M)

# Draw the bounding box on the transformed image
captured_bounding_box = captured_image.copy()
cv2.polylines(captured_bounding_box, [np.int32(roi_trans)], isClosed=True, color=(0, 0, 255), thickness=4)

# Draw the original bounding box on the reference image
ref_bounding_box = reference_image.copy()
cv2.polylines(ref_bounding_box, [np.int32(roi)], isClosed=True, color=(0, 0, 255), thickness=4)

roi_trans = np.array(roi_trans, dtype=np.int32)
mask = np.zeros(captured_image.shape, dtype=np.uint8)  # Black mask
cv2.fillPoly(mask, [roi_trans], (255, 255, 255))  # Fill the polygon with white

# Apply the mask to the original image
masked_image = cv2.bitwise_and(captured_image, mask)

x, y, w, h = cv2.boundingRect(roi_trans)  # Get the bounding rectangle of the polygon

# Crop the area of the image where the polygon is located
cropped_image = masked_image[y:y+h, x:x+w]  # Crop the region of the bounding box

# Display results
plt.figure(figsize=(15, 15))
plt.imshow(cv2.cvtColor(captured_bounding_box, cv2.COLOR_BGR2RGB))
plt.axis('off')  # Hide axes
plt.title('Captured Image with Bounding Box')

plt.figure(figsize=(15, 15))
plt.imshow(cv2.cvtColor(ref_bounding_box, cv2.COLOR_BGR2RGB))
plt.axis('off')  # Hide axes
plt.title('Reference Image with Bounding Box')

plt.figure(figsize=(3, 3))
plt.imshow(cv2.cvtColor(cropped_image, cv2.COLOR_BGR2RGB))
plt.axis('off')  # Hide axes
plt.title('Aligned ROI Crop')
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.