图像畸变矫正——透视变换

2023-05-16

图像畸变矫正——透视变换

由于相机制造精度以及组装工艺的偏差引入的畸变,或者由于照片拍摄时的角度、旋转、缩放等问题, 可能会导致原始图像的失真,如果要修复这些失真,我们可以通过透视变换,对图像进行畸变矫正。

透视变换的原理推导

透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane), 也称作投影映射(Projective Mapping)。透视变换的目的就是把现实中为直线的物体, 在图片上可能呈现为斜线, 通过透视变换转换成直线的变换。

仿射变换(Affine Transformation或 Affine Map) , 又称为仿射映射, 是指在几何中, 图像进行从一个向量空间进行一次线性变换和一次平移, 变换为到另一个向量空间的过程。我们常说的仿射变换是透视变换的一个特例。

图1
以上便是透视变换的原理图,即将源图像通过投影映射,从原图像平面变换到新图像平面。通用的变换公式为:
方程1
(X,Y,Z)是原图像平面坐标点, 对应得到变换后的图像平面坐标点为(X’;Y’;Z’) ,因为我们处理的是二维的图像,所以可以令Z’=1,并将变换后的图像坐标除以Z’,将图片由三维降维为两维,然后可以得到以下方程:
方程2
一般地, 我们令a33=1(方便得到X’,Y’,使方程3等号左侧分母为1), 展开上面公式, 得到一个点的情况:
方程3
方程3中共有8个未知数(aij),如果要解出该未知数,需要列八组方程,即分别在源图像和目标图像上人为选择四个点(通常选择图片的四个顶点)

在源图像上选四个坐标点,分别为A: (x0,y0),(x1,y1),(x2,y2),(x3,y3)

在目标图像上选四个坐标点,分别为B: (X’0,Y’0),(X’1,Y’1),(X’2,Y’2),(X’3,Y’3)

带入方程3,可以得出方程4,如下:
方程4
使用python,将上述推导过程定义为函数WarpPerspectiveMatrix(src, dst),计算出变换矩阵warpMatrix,如下:

import numpy as np
 
def WarpPerspectiveMatrix(src, dst):
    assert src.shape[0] == dst.shape[0] and src.shape[0] >= 4
    #assert语句:用以检查某一条件是否为True,若该条件为False则会给出一个AssertionError。
    #注意这里src和dst的输入并不是图像,而是图像对应的顶点坐标点矩阵。
    nums = src.shape[0]
    A = np.zeros((2*nums, 8)) # A*warpMatrix=B
    B = np.zeros((2*nums, 1))
    for i in range(0, nums):
        A_i = src[i,:]
        B_i = dst[i,:]
        A[2*i, :] = [A_i[0], A_i[1], 1, 0, 0, 0,
                       -A_i[0]*B_i[0], -A_i[1]*B_i[0]]
        B[2*i] = B_i[0]
        
        A[2*i+1, :] = [0, 0, 0, A_i[0], A_i[1], 1,
                       -A_i[0]*B_i[1], -A_i[1]*B_i[1]]
        B[2*i+1] = B_i[1]
 
    A = np.mat(A)  #创建矩阵
    #用A.I求出A的逆矩阵,然后与B相乘,求出warpMatrix
    warpMatrix = A.I * B #求出a_11, a_12, a_13, a_21, a_22, a_23, a_31, a_32
    
    #之后为结果的后处理
    warpMatrix = np.array(warpMatrix).T[0]   #np.array():创建一个数组,.T[0]:将Tensor进行转置
    warpMatrix = np.insert(warpMatrix, warpMatrix.shape[0], values=1.0, axis=0) #插入a_33 = 1
    '''
    np.insert(arr, obj, values, axis)
    #arr原始数组,可一可多,obj插入元素位置,values是插入内容,axis是按行按列插入。
    '''
    warpMatrix = warpMatrix.reshape((3, 3))
    return warpMatrix
 
if __name__ == '__main__':
    '''
    #一个python文件通常有两种使用方法,第一是作为脚本直接执行,第二是 import 到其他的 python 脚本中被调用(模块重用)执行。
    # 因此 if __name__ == 'main': 的作用就是控制这两种情况执行代码的过程,在 if __name__ == 'main': 下的代码只有在第一种情况下
    # (即文件作为脚本直接执行)才会被执行,而 import 到其他脚本中是不会被执行的。
    '''
    print('warpMatrix')
    src = [[10.0, 457.0], [395.0, 291.0], [624.0, 291.0], [1000.0, 457.0]]
    src = np.array(src)
    
    dst = [[46.0, 920.0], [46.0, 100.0], [600.0, 100.0], [600.0, 920.0]]
    dst = np.array(dst)
    
    warpMatrix = WarpPerspectiveMatrix(src, dst)
    print(warpMatrix)

结果为:

warpMatrix
[[-5.01338334e-01 -1.35357643e+00  5.82386716e+02]
 [-1.38100642e-15 -4.84035391e+00  1.38781980e+03]
 [-2.29650079e-19 -4.14856327e-03  1.00000000e+00]]

上述推导过程是为了,让大家更加直观的的了解透视变换。在实际工程上,opencv库早已将上述过程集成为函数,我们选择网上流行的一张图片校验该opencv库中的畸变矫正算法。

图2

代码块为:

import cv2
import numpy as np

img = cv2.imread('photo1.jpg')

result3 = img.copy()

#img = cv2.GaussianBlur(img,(3,3),0)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
"""
cv2.Canny(image,            # 输入原图(必须为单通道图)
          threshold1, 
          threshold2,       # 较大的阈值2用于检测图像中明显的边缘
          [, edges[, 
          apertureSize[,    # apertureSize:Sobel算子的大小
          L2gradient ]]])   # 参数(布尔值):
                              true: 使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),
                              false:使用L1范数(直接将两个方向导数的绝对值相加)。
"""
edges = cv2.Canny(gray,50,150,apertureSize = 3)
#cv2.imwrite("canny.jpg", edges)

'''
注意这里src和dst的输入并不是图像,而是图像对应的顶点坐标点矩阵。
'''
src = np.float32([[207, 151], [517, 285], [17, 601], [343, 731]])
dst = np.float32([[0, 0], [337, 0], [0, 488], [337, 488]])
# 生成透视变换矩阵;进行透视变换
'''
1 cv2.getPerspectiveTransform(src, dst) → retval
 参数说明
src:源图像中待测矩形的四点坐标
sdt:目标图像中矩形的四点坐标
返回由源图像中矩形到目标图像矩形变换的矩阵
'''
m = cv2.getPerspectiveTransform(src, dst)       #适用于一组点
'''
cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
参数为:
src:输入图像
M:变换矩阵
dsize:目标图像shape
flags:插值方式,interpolation方法INTER_LINEAR或INTER_NEAREST
borderMode:边界补偿方式,BORDER_CONSTANT or BORDER_REPLICATE
borderValue:边界补偿大小,常值,默认为0
'''
result = cv2.warpPerspective(result3, m, (337, 488))  #适用于图片
cv2.imshow("src", img)
cv2.imshow("result", result)
cv2.waitKey(0)

输出的结果为
图3

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图像畸变矫正——透视变换 的相关文章

随机推荐

  • VINS fusion软件架构分析(2)---- 从参数文件读取参数

    1 参数配置文件 VINS是利用参数文件yaml统一管理重要的参数 xff0c 主要分为两个参数配置文件 xff0c 如下图 普通参数配置文件 xff0c 如euroc mono imu config yaml相机模型参数配置文件 xff0
  • VINS fusion软件架构分析(5)--- 坐标系转换

    对于VINS代码的解读 xff0c 其中一个重要的知识储备就是理解坐标系间的转换 xff0c 这对于后面代码阅读非常重要 xff0c 因此本章重点解释一下 VINS中有3个坐标系 xff1a 世界坐标系 worldIMU坐标系body相机坐
  • 《算法导论》习题5.3-1 ~ 5.3-7

    算法导论 习题 5 3 1 5 3 7 5 3 5 带星号我抄了一下题目 5 3 6 比较有意思我抄了一下题目 其他的题可以自己对照书 原书第三版 5 3 1 直接考虑第2次循环前 第1次循环后第1个位置的元素是原集合1 n中任意一个元素的
  • ROS:坐标系之间的关系 (map \ odom \ base_link)

    ROS 坐标系之间的关系 map odom base link 在使用ROS进行定位与导航操作时 xff0c 会伴随着各种坐标系 xff0c 并且每种坐标系都有明确的含义 xff0c ros中定义了常见的坐标系 xff0c 并且所有的坐标系
  • 上下拉电阻的作用

    这是在论坛上收集到的一些总结 xff1a 一 OC OD门 xff0c 这种门结构如果不做上拉的话 xff0c 是不能实现电平的高底跳变的 xff0c 不能实现跳变 xff0c 便不能表征数据 二 驱动能力 xff0c 我们看很多的CPU或
  • 实测MySQL 查询结果保留两位小数函数的区别汇总

    MySQL查询结果保留两位小数常用的几个函数的区别 xff0c 使用场景 1 随机函数format x d 2 格式化小数函数format x d 例如 xff1a select format 23456 789 2 或 select fo
  • STLINK怎么与STM32单片机连接

    STLink是ST官方开发的单片机仿真工具 xff0c 可以烧写程序 在线仿真 xff0c 使用非常方便 STLink具有两种接口 xff0c 分别为 1 SWD模式 2 SWIM单总线模式 SWD模式主要针对STM32系列的单片机 xff
  • Ubuntu 18.04系统下创建新用户

    以下介绍在Ubuntu 18 04系统下创建新用户 目录 修改用户权限及删除用户的正确方法 在Ubuntu系统上创建新用户使用 sudo useradd 用户名 命令 xff0c 但只能创建用户 xff0c 不能在 home 中创建用户目录
  • 大数据面试题(一)

    一 hdfs写文件的步骤 答案 xff1a 1 client向NameNode申请上传 xxx txt文件 2 NN向client响应可以上传文件 3 Client向NameNode申请DataNode 4 NN向Client返回DN1 D
  • packages.xml和packages.list全解析

    更多干货 xff0c 欢迎关注微信公众号 tmac lover 今天给大家介绍一下Android系统中保存app信息的两个配置文件 xff0c packages xml和packages list 系统中所有安装的app的基本信息在这里都能
  • linux中vim: command not found

    bash vim command not found 1 查看系统是否安装完整vim 2 安装vim 3 我的解决过程 解决问题步骤 xff1a 1 查看系统是否安装完整vim 执行一下命令 xff1a rpm qa grep vim 如果
  • 【FreeRTOS】任务的创建

    启动流程 LiteOS 和 ucos 第一种和第二种都可以使用 xff0c 由用户选择 xff0c RT Thread 和 FreeRTOS 则默认 创建各个任务 xff0c 然后等待启动调度器创建一个起始任务 xff0c 任务都在这个起始
  • 【FreeRTOS】信号量和互斥量

    二值信号量 同步 xff0c 创建时为空 xff0c 任务1获取 xff08 空 xff09 进入阻塞 xff1b 任务2释放信号量 xff0c 于是任务1获取信号量得以进入就绪状态 资源被获取了 xff0c 信号量值就是 0 xff0c
  • 计算机网络笔记:TCP三次握手和四次挥手过程

    TCP是面向连接的协议 xff0c 连接的建立和释放是每一次面向连接的通信中必不可少的过程 TCP连接的管理就是使连接的建立和释放都能正常地进行 三次握手 TCP连接的建立 三次握手建立TCP连接 若主机A中运行了一个客户进程 xff0c
  • echarts与highcharts学习及区别

    1 echarts用法更广泛 xff0c highcharts更适合特定的某些需求 1 1 echarts和highcharts初始引用 xff0c import as echarts from echarts html要有一个容器 xff
  • 啥是驱动?

    Q amp A 什么是驱动 xff1f 驱动本质上是一个软件程序 xff0c 是内核与硬件之间通信的桥梁 xff0c 为应用程序屏蔽了硬件细节 内核可以通过驱动程序去初始化 释放设备 xff0c 内核可以通过驱动程序与设备做双向的数据交互
  • 基于STM32F1系列的OV7725摄像头初步使用(用于摄像头循迹)

    最近做项目需要用到OV7725 xff0c 于是花了些时间研究 由于OV7725对于工作频率的要求较高 xff0c 因此使用带FIFO的摄像头模块 代码参考自正点原子官方 OV7725资源 引脚说明 以下时关于十八个引脚的说明 xff08
  • CAS SSO单点登录实例

    1 因为是本地模拟sso环境 xff0c 而sso的环境测试需要域名 xff0c 所以需要虚拟几个域名出来 xff0c 步骤如下 xff1a 2 进入目录C Windows System32 drivers etc 3 修改hosts文件
  • Ubuntu屏幕录像软件推荐-Kazam

    由于工作的关系 xff0c 需要经常录制一些软件的操作步骤当做教程 xff0c 现在由于使用了Ubuntu单系统平台 xff0c 以前录制的教程均不能正常运行了 xff0c 需要切换到VM xp里面使用 xff0c 造成很大的不变 xff0
  • 图像畸变矫正——透视变换

    图像畸变矫正 透视变换 由于相机制造精度以及组装工艺的偏差引入的畸变 xff0c 或者由于照片拍摄时的角度 旋转 缩放等问题 xff0c 可能会导致原始图像的失真 xff0c 如果要修复这些失真 xff0c 我们可以通过透视变换 xff0c