opencv 为什么PyRotationWarper.warp和PyRotationWarper.warpPoint似乎应用了不同的变换?

yhxst69z  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(242)

我有一些K和R矩阵,我想应用于图像和该图像中某处的点,以便该点被投影到输出图像中的匹配位置。我使用的是现有图像拼接管道的一部分,它严重依赖于cv2.PyRotationWarper类。一个工作示例如下所示:

import cv2
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from pathlib import Path
import numpy as np
from skimage import data

img = data.cells3d()[34]
img = (255.0 * img / 2**16).astype(np.uint8)[0]
img = cv2.resize(img, (300, 200))
point = [200, 100]
K = np.array(
    [[863.5509, 0.0, 446.5], [0.0, 863.5509, 336.0], [0.0, 0.0, 1.0]], dtype=np.float32
)

R = np.array(
    [
        [0.02657406, 0.99131364, -0.12880631],
        [-0.9981135, 0.01917798, -0.05832428],
        [-0.05534741, 0.13011324, 0.9899532],
    ],
    dtype=np.float32,
)

scale = 890.0
aspect = 1.0

warper = cv2.PyRotationWarper("spherical", scale * aspect)

# warp the image
_, warped_image = warper.warp(
    img,
    K,
    R,
    cv2.INTER_LINEAR,
    cv2.BORDER_REFLECT,
)

# warp the input point
warped_pt = warper.warpPoint(
    point,
    K,
    R,
)

w, h = img.shape[:2][::-1]

# check the maps to see where the transformed pixels came from
_, xmap, ymap = warper.buildMaps(
    (w, h),
    K,
    R,
)

# plot the example
fig, axes = plt.subplots(2, 2, figsize=(10, 8))

axes[0, 0].imshow(img, cmap='gray')
imx = axes[0, 1].imshow(xmap)
imy = axes[1, 0].imshow(ymap)
axes[1, 1].imshow(warped_image, cmap='gray')

axes[0, 0].add_patch(Circle(point, 3, color='red',))
axes[1, 1].add_patch(Circle(warped_pt, 3, color='red'))

axes[0, 0].set(title=f"original image; point: {point}")
axes[0, 1].set(title="xmap")
axes[1, 0].set(title="ymap")
axes[1, 1].set(title=f"warped image: point: [{warped_pt[0]:.2f}, {warped_pt[1]:.2f}]")
cbx = plt.colorbar(imx, ax=axes[0, 1], orientation="vertical")
cby = plt.colorbar(imy, ax=axes[1, 0], orientation="vertical")

plt.tight_layout()

但是点被投影到一个疯狂的位置[-353.75, 1582.54],而不是我期望的位置:大致为[100, 100]。调试图如下所示:

很明显,我在这里遗漏了一些东西,也许只是不理解warpwarpPoint函数应该如何工作。怎么回事?

vmpqdwk3

vmpqdwk31#

我假设warper.warp()返回的第一个值与问题直接相关。因此,我只是通过减去返回的数量来校正warp_point坐标:warp_pt_corrected=np.array(warp_pt)-np.array(corrected)。在应用校正后,投影看起来不错。

import cv2
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from pathlib import Path
import numpy as np
from skimage import data

img = data.cells3d()[34]
img = (255.0 * img / 2**16).astype(np.uint8)[0]
img = cv2.resize(img, (300, 200))
point = [200, 100]
K = np.array(
    [[863.5509, 0.0, 446.5], [0.0, 863.5509, 336.0], [0.0, 0.0, 1.0]], dtype=np.float32
)

R = np.array(
    [
        [0.02657406, 0.99131364, -0.12880631],
        [-0.9981135, 0.01917798, -0.05832428],
        [-0.05534741, 0.13011324, 0.9899532],
    ],
    dtype=np.float32,
)

scale = 890.0
aspect = 1.0

warper = cv2.PyRotationWarper("spherical", scale * aspect)

# warp the image
correction, warped_image = warper.warp(
    img,
    K,
    R,
    cv2.INTER_LINEAR,
    cv2.BORDER_REFLECT,
)

# warp the input point
warped_pt = warper.warpPoint(
    point,
    K,
    R,
)

w, h = img.shape[:2][::-1]

# check the maps to see where the transformed pixels came from
_, xmap, ymap = warper.buildMaps(
    (w, h),
    K,
    R,
)

# plot the example
fig, axes = plt.subplots(2, 2, figsize=(10, 8))

axes[0, 0].imshow(img, cmap='gray')
imx = axes[0, 1].imshow(xmap)
imy = axes[1, 0].imshow(ymap)
axes[1, 1].imshow(warped_image, cmap='gray')

warped_pt_corrected=np.array(warped_pt)-np.array(correction)

axes[0, 0].add_patch(Circle(point, 3, color='red',))
axes[1, 1].add_patch(Circle(warped_pt_corrected, 3, color='red'))

axes[0, 0].set(title=f"original image; point: {point}")
axes[0, 1].set(title="xmap")
axes[1, 0].set(title="ymap")
axes[1, 1].set(title=f"warped image: point: [{warped_pt_corrected[0]:.2f}, {warped_pt_corrected[1]:.2f}]")
cbx = plt.colorbar(imx, ax=axes[0, 1], orientation="vertical")
cby = plt.colorbar(imy, ax=axes[1, 0], orientation="vertical")

plt.tight_layout()

让我再举另一个例子来更好地说明修正是适当的:

相关问题