OpenCV仿射变换与透视变换实战

目录

一、引言

二、仿射变换

[1. 基本概念](#1. 基本概念)

[2. OpenCV实现](#2. OpenCV实现)

[3. 应用示例:图像校正](#3. 应用示例:图像校正)

三、透视变换

[1. 基本概念](#1. 基本概念)

[2. OpenCV实现](#2. OpenCV实现)

[3. 应用示例:视角转换](#3. 应用示例:视角转换)

四、完整代码示例

五、仿射变换与透视变换的区别

1、基本概念

2、核心区别对比​编辑

3、应用场景区别

4、视觉效果区别

六、应用场景

[1. 仿射变换应用](#1. 仿射变换应用)

[2. 透视变换应用](#2. 透视变换应用)

七、注意事项

八、总结


一、引言

在计算机视觉中,几何变换是图像处理的基础操作之一。除了基本的缩放、旋转和平移外,仿射变换和透视变换是两种更高级的几何变换技术,它们可以实现更复杂的图像变形效果。本文将详细介绍这两种变换的原理和在OpenCV中的实现方法。

二、仿射变换

1. 基本概念

仿射变换是一种保持平行性和共线性的几何变换,它可以看作是平移、旋转、缩放和倾斜的组合。在仿射变换中,原图中的直线变换后仍然是直线,平行线变换后仍然是平行线。

仿射变换的数学表达式为:

x' y'\] = \[x y 1\] \[\[a b\]\[c d\]\[tx ty\]

其中,(x, y)是原图坐标,(x', y')是变换后的坐标,矩阵[[a b][c d]]负责旋转、缩放和倾斜,(tx, ty)负责平移。

2. OpenCV实现

在OpenCV中,仿射变换通过cv2.warpAffine()函数实现,需要先获取仿射变换矩阵。获取变换矩阵有两种方法:

方法1:使用cv2.getAffineTransform()

该函数需要原图中三个点和变换后对应三个点的坐标,自动计算仿射变换矩阵。

//python

原图中的三个点

pts1 = np.float32([[50, 50], [200, 50], [50, 200]])

变换后对应的三个点

pts2 = np.float32([[10, 100], [200, 50], [100, 250]])

获取仿射变换矩阵

M = cv2.getAffineTransform(pts1, pts2)

进行仿射变换

dst = cv2.warpAffine(img, M, (cols, rows))

方法2:组合基本变换

可以手动构造旋转、缩放、倾斜等基本变换的矩阵,然后组合成仿射变换矩阵。

3. 应用示例:图像校正

仿射变换常用于校正倾斜的图像,例如文档扫描后的校正。

三、透视变换

1. 基本概念

透视变换(也称为投影变换)是一种更一般的几何变换,它可以保持共线性但不保持平行性。透视变换可以将3D空间中的物体投影到2D平面上,常用于实现"鸟瞰图"效果。

透视变换的数学表达式为:

x' y' z'\] = \[x y 1\] \[\[a b c\]\[d e f\]\[g h i\]

其中,(x, y)是原图坐标,(x'/z', y'/z')是变换后的坐标。

2. OpenCV实现

在OpenCV中,透视变换通过cv2.warpPerspective()函数实现,需要先获取透视变换矩阵。获取变换矩阵的方法是使用cv2.getPerspectiveTransform()函数,该函数需要原图中四个点和变换后对应四个点的坐标。

原图中的四个点(四边形)

pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])

变换后对应的四个点(矩形)

pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])

获取透视变换矩阵

M = cv2.getPerspectiveTransform(pts1, pts2)

进行透视变换

dst = cv2.warpPerspective(img, M, (300, 300))

3. 应用示例:视角转换

透视变换常用于将倾斜视角的图像转换为正视图,例如将拍摄的名片、文档转换为平面视图。

四、完整代码示例

//python实现

python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

 读取图像
img = cv2.imread('lena.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rows, cols, _ = img_rgb.shape

 1. 仿射变换
 定义原图和变换后的三个点
pts1_affine = np.float32([[50, 50], [200, 50], [50, 200]])
pts2_affine = np.float32([[10, 100], [200, 50], [100, 250]])
 获取仿射变换矩阵
M_affine = cv2.getAffineTransform(pts1_affine, pts2_affine)
 进行仿射变换
affine_result = cv2.warpAffine(img_rgb, M_affine, (cols, rows))

2. 透视变换

 定义原图和变换后的四个点

pts1_perspective = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])

pts2_perspective = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])

 获取透视变换矩阵

M_perspective = cv2.getPerspectiveTransform(pts1_perspective, pts2_perspective)

 进行透视变换

perspective_result = cv2.warpPerspective(img_rgb, M_perspective, (300, 300))

显示结果

plt.figure(figsize=(12, 8))


plt.subplot(131)

plt.imshow(img_rgb)

plt.title('Original Image')

plt.axis('off')


plt.subplot(132)

plt.imshow(affine_result)

plt.title('Affine Transformation')

plt.axis('off')


plt.subplot(133)

plt.imshow(perspective_result)

plt.title('Perspective Transformation')

plt.axis('off')


plt.tight_layout()

plt.show()

//C++实现

cpp 复制代码
include <opencv2/opencv.hpp>
include <iostream>

using namespace cv;
using namespace std;

int main() 
{
    //读取图像
    Mat img = imread("lena.jpg");
    if (img.empty()) {
        cout << "无法读取图像文件" << endl;
        return 1;
    }
    
    Mat img_rgb;
    cvtColor(img, img_rgb, COLOR_BGR2RGB); // 转换为RGB格式用于显示
    
    int rows = img.rows;
    int cols = img.cols;
    
    //1. 仿射变换
    //定义原图和变换后的三个点
    vector<Point2f> pts1_affine(3);
    vector<Point2f> pts2_affine(3);
    
    pts1_affine[0] = Point2f(50, 50);
    pts1_affine[1] = Point2f(200, 50);
    pts1_affine[2] = Point2f(50, 200);
    
    pts2_affine[0] = Point2f(10, 100);
    pts2_affine[1] = Point2f(200, 50);
    pts2_affine[2] = Point2f(100, 250);
    
    //获取仿射变换矩阵
    Mat M_affine = getAffineTransform(pts1_affine, pts2_affine);
    //进行仿射变换
    Mat affine_result;
    warpAffine(img, affine_result, M_affine, Size(cols, rows));
    
    //2. 透视变换
    //定义原图和变换后的四个点
    vector<Point2f> pts1_perspective(4);
    vector<Point2f> pts2_perspective(4);
    
    pts1_perspective[0] = Point2f(56, 65);
    pts1_perspective[1] = Point2f(368, 52);
    pts1_perspective[2] = Point2f(28, 387);
    pts1_perspective[3] = Point2f(389, 390);
    
    pts2_perspective[0] = Point2f(0, 0);
    pts2_perspective[1] = Point2f(300, 0);
    pts2_perspective[2] = Point2f(0, 300);
    pts2_perspective[3] = Point2f(300, 300);
    
    //获取透视变换矩阵
    Mat M_perspective = getPerspectiveTransform(pts1_perspective, pts2_perspective);
    //进行透视变换
    Mat perspective_result;
    warpPerspective(img, perspective_result, M_perspective, Size(300, 300));
    
    //显示结果
    namedWindow("Original Image", WINDOW_NORMAL);
    namedWindow("Affine Transformation", WINDOW_NORMAL);
    namedWindow("Perspective Transformation", WINDOW_NORMAL);
    
    imshow("Original Image", img);
    imshow("Affine Transformation", affine_result);
    imshow("Perspective Transformation", perspective_result);
    
    waitKey(0);
    destroyAllWindows();
    
    return 0;
}

五、仿射变换与透视变换的区别

1、基本概念

仿射变换 :保持平行性和共线性的几何变换,可看作平移、旋转、缩放和倾斜的组合。

透视变换 :更一般的几何变换,只保持共线性,可模拟真实世界的透视效果。

2、核心区别对比

3、应用场景区别

(1)仿射变换适用场景 :

图像校正(如倾斜文档校正)

图像配准

数据增强(生成不同角度的训练样本)

简单的图像变形动画

(2)透视变换适用场景 :

文档扫描(将拍摄的文档转换为平面视图)

视角转换(如将监控画面转换为鸟瞰图)

增强现实(将虚拟物体投影到真实场景)

全景图像拼接

地图投影

4、视觉效果区别

仿射变换 后的图像边缘仍然平行,适合保持物体形状的变换
透视变换会产生近大远小的效果,更符合人眼观察真实世界的方式

六、应用场景

1. 仿射变换应用

  • 图像校正:校正倾斜的文档、照片
  • 图像配准:将多幅图像对齐到同一坐标系
  • 数据增强:生成不同角度、尺度的训练样本
  • 动画效果:实现图像的复杂变形动画

2. 透视变换应用

  • 文档扫描:将拍摄的文档转换为平面视图
  • 地图投影:将3D地球投影到2D地图
  • 增强现实:将虚拟物体投影到真实场景
  • 全景拼接:将多张照片拼接成全景图
  • 交通监控:将监控画面转换为鸟瞰图,便于车辆检测和跟踪

七、注意事项

  1. 点的选择:在使用cv2.getAffineTransform()和cv2.getPerspectiveTransform()时,点的选择非常重要,应选择图像中明显的特征点,以提高变换精度。

  2. 图像边界:变换后图像可能会超出原图像范围,可以通过设置borderMode参数来处理边界,常用的有cv2.BORDER_CONSTANT(常量填充)和cv2.BORDER_REPLICATE(复制边界像素)。

  3. 性能优化:对于大尺寸图像,透视变换可能比较耗时,可以考虑先缩小图像进行变换,再放大到原尺寸。

  4. 逆变换:如果需要从变换后的图像恢复原图,可以使用cv2.invertAffineTransform()(仿射变换)或np.linalg.inv()(透视变换)计算逆变换矩阵,然后应用逆变换。

八、总结

本文详细介绍了OpenCV中仿射变换和透视变换的原理、实现方法和应用场景。仿射变换适用于需要保持平行性的场景,而透视变换适用于需要模拟真实透视效果的场景。

相关推荐
中科天工2 小时前
AGV物流+机器视觉:解锁包装车间自动化升级的核心密码
大数据·人工智能·智能
problc2 小时前
肉包 Roubao:首款无需电脑的开源 AI 手机自动化助手
人工智能·智能手机·开源
胡伯来了2 小时前
11 Transformers - 使用Pipeline处理音频
人工智能·transformer·transformers·音频处理·大数据模型
泡泡茶壶_ovo2 小时前
Zero-Shot Image Captioning with Multi-type Entity Representations(AAAI 2025)
人工智能·深度学习·计算机视觉·imagecaptioning·multimodal
tap.AI2 小时前
RAG系列(五)生产部署、成本优化与系统评估
人工智能
沃彼特2 小时前
不用任何软件,检测闪存(SD卡U盘)的真实容量检测非常简单的测试方式,没有之一,不会用电脑都会用这个。
人工智能·目标检测·数据挖掘
Baihai_IDP2 小时前
LLM 扩展方式的三年演进之路:复杂之后,回归简单
人工智能·面试·llm
QYR_112 小时前
CAGR2.9%,全球石英波片市场稳步扩张,中国市场增速领跑
大数据·网络·人工智能
2501_940007862 小时前
论文检测网站全解析:类型、功能与选择指南
人工智能