用OpenCV进行透视变换

1. 引言

欢迎回来!今天我们将焦点聚焦在我在图像处理中最喜欢的话题之一——透视变换。使用该技术,可以灵活方便的实现各种各样好玩的特效。

闲话少说,我们直接开始吧!

2. 单应矩阵

我们首先展开对单应矩阵的深入研究。作为图像处理的基本工具,它在捕捉图像中的几何变换方面发挥着至关重要的作用。更具体地说,它是实现透视变换的秘密武器。

单应矩阵被定义为图像的两个平面投影之间的映射。它由齐次坐标空间中的3x3变换矩阵表示。这些变换可以是旋转、平移、缩放等操作的组合。

我们用示意图总结如下:
在这里插入图片描述

3. 举个栗子

虽然上图简明地定义了常见的转换,但是如果我们将其应用到输入和输出为图像操作会怎样?根据变换,我们需要几个点来计算单应矩阵。让我们来做吧!像往常一样,让我们首先导入必要的库,如下:

# Import libraries
from skimage.io import imread, imshow
import matplotlib.pyplot as plt
import numpy as np
from skimage import transform

接着导入我们需要的测试图像,代码如下:

# Display the original image

image = imread('painting.png')
plt.figure(figsize=(20,20))
plt.imshow(image)
plt.title('Original Image', fontsize=20, weight='bold')
plt.axis('off')
plt.show()

结果如下:
在这里插入图片描述

4. 计算变换矩阵

接着我们想对这幅画有一个自上而下的视图。我们需要计算单应矩阵。我们必须确定这幅画明确的角点。在这种情况下,我使用画图应用程序来识别画的四个角点坐标:

# Source points
src = np.array([879, 625,                    # top left
                431, 2466,                   # bottom left
                3251, 61,                    # top right
                3416, 2767]).reshape((4, 2)) # bottom right

为了执行单应性变换,我们需要一组与源点相对应的目标点。这些目标点表示我们希望源点在输出图像中的位置。对于自上而下的视图,这里我们引用源点的最小值和最大值x和y:

# Destination points
dst = np.array([
    [np.min(src[:, 0]), np.min(src[:, 1])],  # top left
    [np.min(src[:, 0]), np.max(src[:, 1])],  # bottom left
    [np.max(src[:, 0]), np.min(src[:, 1])],  # top right
    [np.max(src[:, 0]), np.max(src[:, 1])],  # bottom right
])

接着我们用以下代码计算单应矩阵,如下:

tform = transform.estimate_transform('projective', src, dst)

5. 透视变换

经过上述处理,我们有了执行透视变换所需要的单应性矩阵,接着我们来执行对应的透视变换,如下:

tf_img = transform.warp(image, tform.inverse)
fig, ax = plt.subplots(figsize=(20,20))
ax.imshow(tf_img)
_ = ax.set_title('projective transformation')

得到结果如下:
在这里插入图片描述

6. 美化显示效果

观察上图,考虑到图像外围添加了白色像素,输出看起来很奇怪,我们可以编辑出代码来裁剪这些奇怪的墙和额外的像素:

# Load the image
image = imread('painting.png')

# Source points
src = np.array([879, 625,                    # top left
                431, 2466,                   # bottom left
                3251, 61,                    # top right
                3416, 2767]).reshape((4, 2)) # bottom right

# Estimate the width and height from the source points
width = np.max(src[:, 0]) - np.min(src[:, 0])
height = np.max(src[:, 1]) - np.min(src[:, 1])

# Destination points (forming a box shape)
dst = np.array([
    [0, 0],
    [0, height],
    [width, 0],
    [width, height]
])

# Compute the projective transform
tform = transform.estimate_transform('projective', src, dst)

# Apply the transformation
warped_image = transform.warp(image, tform.inverse, output_shape=(height, width))

# Convert the warped image to uint8
warped_image_uint8 = (warped_image * 255).astype(np.uint8)

# Display the transformed and cropped image
plt.figure(figsize=(20,20))
plt.imshow(warped_image_uint8)
plt.title('Transformed and Cropped Image', fontsize=20, weight='bold')
plt.axis('off')
plt.show()

最终的显示效果如下:
在这里插入图片描述

7. 总结

经过我们一步一步的优化,我们最终得到了,一幅美丽而干净的自上而下的油画。一般来说,一旦我们有了单应矩阵,我们也可以用它来变换一幅图像,使其与另一幅图像的视角对齐。这对于图像拼接等应用非常有用!

嗯嗯,您学废了嘛?

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenCV是一个强大的计算机视觉库,它提供了丰富的图像处理和计算机视觉算法,包括透视变换。在Python中,使用OpenCV进行透视变换通常涉及到`cv2.getPerspectiveTransform()`和`cv2.warpPerspective()`这两个核心函数。 1. **获取透视变换矩阵**: `cv2.getPerspectiveTransform(src, dst)` 函数接收两个输入:源图像中的四个点(定义了源图像的不规则矩形区域),以及目标矩形区域的对应点。这个函数会计算一个透视变换矩阵,用于将源图像映射到目标矩形。 2. **应用透视变换**: `cv2.warpPerspective(img, M, dsize, flags=0, borderMode=BORDER_CONSTANT, borderValue=None)` 用这个函数来实际执行变换,其中 `img` 是源图像,`M` 是从上面获得的透视变换矩阵,`dsize` 是目标图像的大小,`flags` 可选参数影响变换的行为(如插值方法),`borderMode` 和 `borderValue` 控制边界像素的处理方式。 一个简单的例子可能如下所示: ```python import cv2 import numpy as np # 假设src_points和dst_points是四点坐标 src_points = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]]) dst_points = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]]) # 计算透视变换矩阵 M = cv2.getPerspectiveTransform(src_points, dst_points) # 读取原图并进行透视变换 img = cv2.imread('input.jpg') warped_img = cv2.warpPerspective(img, M, (300, 300)) # 显示原图和变换后的图像 cv2.imshow('Original', img) cv2.imshow('Warped', warped_img) cv2.waitKey(0) cv2.destroyAllWindows() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵卓不凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值