我在Vscode学OpenCV 几何变换(缩放、翻转、仿射变换、透视、重映射)

几何变换指的是将一幅图像映射到另一幅图像内的操作。

  1. cv2.warpAffine:使用仿射变换矩阵对图像进行变换,可以实现平移、缩放和旋转等操作。
  2. cv2.warpPerspective:使用透视变换矩阵对图像进行透视变换,可以实现镜头校正、图像纠偏等操作。
  3. cv2.getAffineTransform:计算仿射变换矩阵,根据输入的三个点对之间的关系来生成一个2x3的矩阵。
  4. cv2.getPerspectiveTransform:计算透视变换矩阵,根据输入的四个点对之间的关系来生成一个3x3的矩阵。
  5. cv2.resize:调整图像的大小,可以根据指定的尺寸或比例因子来进行缩放操作。
  6. cv2.flip:对图像进行翻转操作,可以在水平、垂直或两者方向上进行翻转。
  7. cv2.rotate:对图像进行旋转操作,可以按照指定的角度对图像进行顺时针或逆时针旋转。

这些函数可以在OpenCV中灵活使用,以实现各种图像的几何变换。通过调整参数和变换矩阵,可以达到所需的图像效果和变换结果。

CV 几何变换

  • 一、缩放
    • [1.1 写法](#1.1 写法)
    • [1.1 改变图像的参数dsize的值](#1.1 改变图像的参数dsize的值)
    • [1.2通过参数 fx 和 fy 指定](#1.2通过参数 fx 和 fy 指定)
    • 1.3什么是插值
  • 二、翻转
    • [2.1 语句 y=cv2.flip(img,1) 会使图像绕着 y 轴进行翻转。](#2.1 语句 y=cv2.flip(img,1) 会使图像绕着 y 轴进行翻转。)
    • [2.2 语句 xy=cv2.flip(img,-1) 会使图像同时绕着 x 轴和 y 轴进行翻转。](#2.2 语句 xy=cv2.flip(img,-1) 会使图像同时绕着 x 轴和 y 轴进行翻转。)
    • [2.3 语句 x=cv2.flip(img,0) 会使图像绕着 x 轴进行翻转。](#2.3 语句 x=cv2.flip(img,0) 会使图像绕着 x 轴进行翻转。)
  • 三、仿射变换
    • [3.1 平移](#3.1 平移)
      • [3.1.1 代码及效果](#3.1.1 代码及效果)
      • [3.1.2 平移再缩放](#3.1.2 平移再缩放)
    • [3.2 旋转](#3.2 旋转)
      • [3.2.1 代码及效果](#3.2.1 代码及效果)
    • [3.3 cv2.getAffineTransform:计算仿射变换矩阵](#3.3 cv2.getAffineTransform:计算仿射变换矩阵)
      • [3.3.1 代码](#3.3.1 代码)
  • 四、透视
      • [4.1 `cv2.getPerspectiveTransform()` 转换矩阵](#4.1 cv2.getPerspectiveTransform() 转换矩阵)
      • [4.2 代码及效果](#4.2 代码及效果)
  • 五、重映射
    • [5.1 复制](#5.1 复制)
    • [5.2 翻转](#5.2 翻转)
      • [5.2.1 绕着x轴](#5.2.1 绕着x轴)
      • [5.2.2 绕y轴翻转](#5.2.2 绕y轴翻转)
      • [5.2.3 绕x轴、y轴翻转](#5.2.3 绕x轴、y轴翻转)
      • [5.2.4 x轴、y轴互换](#5.2.4 x轴、y轴互换)
    • [5.3 图像缩放](#5.3 图像缩放)

一、缩放

或者仿射变换
dst = cv2.resize( src, dsize[, fx[, fy[, interpolation]]] )

 dst 代表输出的目标图像,该图像的类型与 src 相同,其大小为 dsize(当该值非零时),或者可以通过 src.size()fx、fy 计算得到。

 src 代表需要缩放的原始图像。

 dsize 代表输出图像大小。

 fx 代表水平方向的缩放比例。

 fy 代表垂直方向的缩放比例。

 interpolation 代表插值方式

1.1 写法

py 复制代码
# 指定目标尺寸
resized_image = cv2.resize(image, (new_width, new_height))

# 指定缩放比例因子
resized_image = cv2.resize(image, None, fx=scale_factor, fy=scale_factor)

# 指定目标尺寸和插值方法
resized_image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_NEAREST)

原图:

1.1 改变图像的参数dsize的值

无论有fx,fy,都是由于dszie决定目标图像的大小,colws,rows

fx=(double)dsize.width/src.cols
fy=(double)dsize.height/src.rows```

1.2通过参数 fx 和 fy 指定

dsize的值为None,通过目标的参数fx,fy来实现的。
dsize(round(fx*src.cols),round(fy*src.rows))

1.3什么是插值

几何变换(如调整大小)期间确定无法直接映射的像素点值的必要性。当你放大图像时,会引入一些在原始图像中没有相应值的新像素。插值方法用于估算这些新像素的值。

cpp 复制代码
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1=cv.imread("./Pic/test_img.jpg")
rows,cols=img1.shape[:2]
print(rows)
print(cols)

部分介绍

  • 最近邻插值:最近邻插值方法会选择最接近目标像素位置的原始像素的值作为新像素的值。这种方法计算简单,但可能会导致图像的锯齿状边缘和失真。

  • 双线性插值:双线性插值方法会根据目标像素位置周围的四个最近原始像素的值进行加权平均,以计算新像素的值。这种方法可以产生较平滑的图像,但可能会导致细节的模糊。

  • 双三次插值:双三次插值方法会根据目标像素位置周围的16个最近原始像素的值进行加权平均,以计算新像素的值。这种方法可以产生更平滑的图像,但计算复杂度较高。

选择哪种插值方法取决于应用的需求。如果需要保留图像的细节和边缘,可以选择双线性或双三次插值。如果需要快速计算并可以容忍一些失真,可以选择最近邻插值。

总之,插值方法在图像缩放中起着重要的作用,可以影响图像质量和计算效率。根据具体需求选择适当的插值方法是很重要的。

二、翻转

在图像处理中,旋转和翻转是两种不同的操作。

·

旋转 意味着围绕图像的中心或其他指定点按某个角度旋转图像。这会导致图像内容的重组,但不会改变内容本身的方向。在 OpenCV 中,你可以使用 cv2.rotate 函数来旋转图像。

·
翻转 意味着以水平或垂直轴为对称轴来颠倒图像内容。水平翻转会使图像左右颠倒,而垂直翻转则会使图像上下颠倒。在 OpenCV 中,你可以使用 cv2.flip 函数来实现图像的翻转。

·

总结来说,旋转是根据一个角度来调整图像的方向,而翻转是基于图像的对称轴来颠倒图像内容。

dst = cv2.flip( src, flipCode )

#src 代表了原始像素点(源像素),dst 代表了目标像素点(目标像素)

dst 代表和原始图像具有同样大小、类型的目标图像。

src 代表要处理的原始图像。

flipCode 翻转的方式(水平翻转、垂直翻转或同时进行水平和垂直翻转)

2.1 语句 y=cv2.flip(img,1) 会使图像绕着 y 轴进行翻转。

py 复制代码
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
imgx=cv.imread("./Pic/test_img.jpg")
dst=cv.flip(imgx,1)
plt.imshow(dst[:,:,::-1])

2.2 语句 xy=cv2.flip(img,-1) 会使图像同时绕着 x 轴和 y 轴进行翻转。

py 复制代码
dst=cv.flip(imgx,-1)
plt.imshow(dst[:,:,::-1])

2.3 语句 x=cv2.flip(img,0) 会使图像绕着 x 轴进行翻转。

python 复制代码
dst=cv.flip(imgx,0)
plt.imshow(dst[:,:,::-1])

三、仿射变换

仿射变换是一种线性变换,可以通过矩阵的乘法来描述。这种变换在保持图像中的平行性和直线性方面非常强大,因此在图像处理和计算机视觉领域得到广泛应用。它能够实现平移、旋转、缩放和剪切等操作,并且在变换后仍然能够保持空间关系的几何特性。

dst = cv2.warpAffine( src, M, dsize[, flags[, borderMode[, borderValue]]] )

  • src: 输入图像,即需要进行仿射变换的图像。
  • M: 变换矩阵,描述了平移、旋转和缩放等操作。
  • dsize: 输出图像的大小,即变换后的图像的尺寸。
  • flags: 插值方法的标志。用于指定在变换过程中如何对像素进行插值。这是可选参数。
  • borderMode: 边界模式,指定了当像素越界时的处理方式(例如镜像、填充等)。这也是一个可选参数。
  • borderValue: 当使用常量边界模式时,指定边界填充的数值。这同样是一个可选参数。

在运用中就简化成
dst = cv2.warpAffine( src , M , dsize )

3.1 平移

平移是一种基本的仿射变换操作,它将图像沿着给定的方向进行移动。

【图像平移将图像按照指定方向和距离,移动到相应的位置】

md 复制代码
M = | 1 0 tx |
    | 0 1 ty |

在这里,tx 和 ty 分别表示沿 x 和 y 方向的平移量。当应用这个平移矩阵时,图像中的每个像素将按照指定的偏移量进行移动。

只需提供适当的变换矩阵,可以很容易地实现图像的平移操作
dst = cv2.warpAffine( src , M , dsize )

img:输入图像

M: 2*3移动矩阵(注意:将M设置为np.float32类型的Numpy数组。)

dsize:输出图像的大小注意:输出图像的大小,它应该是(宽度,高度)的形式。请记住,width=列数, height=行数。

3.1.1 代码及效果

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

img1 = cv.imread('./Pic/test_img.jpg')

# 平移
rows, cols = img1.shape[:2]
M = np.float32([[1, 0, 100], [0, 1, 50]])
dst = cv.warpAffine(img1, M, (cols, rows))

# 显示
fig, axes = plt.subplots(1, 2, figsize=(12, 6))

axes[0].imshow(cv.cvtColor(img1, cv.COLOR_BGR2RGB))
axes[0].set_title("Original")

axes[1].imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
axes[1].set_title("Change")
plt.show()

3.1.2 平移再缩放

更改dsize的大小

3.2 旋转

retval=cv2.getRotationMatrix2D(center, angle, scale)

在这里,cv2.getRotationMatrix2D()函数用于生成一个旋转矩阵,其参数的含义如下:

  • center:旋转的中心点坐标,通常以元组 (x, y) 的形式表示。在图像处理中,(0, 0) 通常代表图像的左上角。

  • angle:旋转角度,以度为单位。正数表示逆时针旋转,负数表示顺时针旋转。

  • scale:可选的缩放因子。如果不需要对图像进行缩放,可以将其设置为1。如果想要按比例缩放图像,可以提供缩放因子。

该函数返回一个2x3的变换矩阵,将它应用到原始图像上可以实现指定中心点、角度和缩放比例的旋转。

3.2.1 代码及效果

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

img = cv.imread('./Pic/test_img.jpg')

# 获取图像尺寸
rows, cols = img.shape[:2]

# 旋转角度为90度
theta = 90
theta_rad = np.deg2rad(theta)

# 构造旋转矩阵
M = cv.getRotationMatrix2D((cols / 2, rows / 2), theta, 1)

# 进行图像旋转
dst = cv.warpAffine(img, M, (cols, rows))

# 显示图像
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Original")

axes[1].imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
axes[1].set_title("Rotated")
plt.show()
python 复制代码
M = cv.getRotationMatrix2D((cols/ 2, rows / 2), 45, 0.5)

3.3 cv2.getAffineTransform:计算仿射变换矩阵

retval=cv2.getAffineTransform(src, dst)

 src 代表输入图像的三个点坐标。

 dst 代表输出图像的三个点坐标。

3.3.1 代码

python 复制代码
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
x1, y1 = 100, 100
x2, y2 = 200, 300
x3, y3 = 100, 200

u1, v1 = 150, 150
u2, v2 = 250, 150
u3, v3 = 150, 250

img = cv.imread('./Pic/test_img.jpg')

# 获取图像尺寸
rows, cols = img.shape[:2]

# 定义原始图像上的三个点和目标图像上的三个对应点
pts_original = np.float32([[x1, y1], [x2, y2], [x3, y3]])
pts_target = np.float32([[u1, v1], [u2, v2], [u3, v3]])

# 获取仿射变换矩阵
M = cv.getAffineTransform(pts_original, pts_target)

# 进行仿射变换
dst = cv.warpAffine(img, M, (cols, rows))

# 显示图像
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Original")

axes[1].imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
axes[1].set_title("Transformed")
plt.show()

四、透视

dst = cv2.warpPerspective( src, M, dsize[, flags[, borderMode[, borderValue]]] )
cv2.warpPerspective()函数用于执行透视变换,它接受以下参数:

  1. src: 输入图像。这是要进行透视变换的原始图像。

  2. M: 变换矩阵。这是通过cv2.getPerspectiveTransform()或其他类似函数计算得到的透视变换矩阵。

  3. dsize: 输出图像的大小,表示为 (width, height)

  4. flags(可选参数): 这是一个插值方法的标志,用于指定如何在变换过程中对图像进行插值。默认情况下为cv2.INTER_LINEAR,这意味着使用线性插值。其他可能的值包括cv2.INTER_NEAREST(最近邻插值)、cv2.INTER_CUBIC(立方插值)等。

  5. borderMode(可选参数): 用于定义边界像素的模式。默认为cv2.BORDER_CONSTANT,表示将边界填充为常数值。其他可能的值包括cv2.BORDER_REFLECT(边界像素的镜像反射)和cv2.BORDER_WRAP(边界像素的重复等)。

  6. borderValue(可选参数): 当borderModecv2.BORDER_CONSTANT时,可以指定边界填充的常数值。默认为0。

4.1 cv2.getPerspectiveTransform() 转换矩阵

可以使用函数 cv2.getPerspectiveTransform() 生成适用于 cv2.warpPerspective() 的转换矩阵。该函数的语法格式为:

python 复制代码
retval = cv2.getPerspectiveTransform(src, dst)

其中,参数含义如下:

  • src:代表输入图像的四个顶点的坐标。

  • dst:代表输出图像的四个顶点的坐标。

需要注意的是,src 参数和 dst 参数都是包含四个点的数组,与仿射变换函数 cv2.getAffineTransform() 中的三个点是不同的。在实际使用中,我们可以根据需求控制 src 中的四个点映射到 dst 中的四个点。

4.2 代码及效果

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

# 定义原始图像上的四个点和目标图像上的四个对应点
src_points = np.float32([[100, 100], [200, 300], [100, 200], [300, 150]])
dst_points = np.float32([[150, 150], [250, 150], [150, 250], [300, 200]])

img = cv.imread('./Pic/test_img.jpg')

# 获取透视变换矩阵
M = cv.getPerspectiveTransform(src_points, dst_points)

# 进行透视变换
dst = cv.warpPerspective(img, M, (img.shape[1], img.shape[0]))

# 显示图像
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Original")

axes[1].imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
axes[1].set_title("Transformed")
plt.show()

五、重映射

重映射是指将图像中的像素从一个位置映射到另一个位置的过程。在计算机视觉和图像处理中,重映射通常用于图像几何变换(如旋转、缩放、仿射变换、透视变换等)以及校正畸变等操作。

在重映射过程中,我们需要定义一个映射关系,将输入图像中的每个像素映射到输出图像中的相应位置。这个映射关系可以通过变换矩阵(如仿射变换矩阵或透视变换矩阵)来实现,也可以通过自定义的像素级映射函数来完成。一旦建立了映射关系,就可以根据该关系对图像进行重映射,从而实现所需的变换效果。

在OpenCV中,重映射通常涉及到两个主要函数:cv2.remap()cv2.warpAffine()cv2.warpPerspective()。前者允许用户提供自定义的映射关系,而后者则使用预定义的变换矩阵来执行重映射。

5.1 复制

当使用 cv2.remap() 函数来实现图像复制时,我们可以通过以下步骤进行处理:

  1. 创建网格:首先,我们需要创建一个与原始图像大小相同的网格。这个网格将用于映射坐标值。
python 复制代码
height, width = img.shape[:2]
map_x, map_y = np.meshgrid(np.arange(width), np.arange(height))
  1. 设置 map1 和 map2 的值:接下来,我们将 map1 的值设定为对应位置上的 x 轴坐标值,将 map2 的值设定为对应位置上的 y 轴坐标值。
python 复制代码
map1 = map_x
map2 = map_y
  1. 使用 remap 函数实现图像复制 :将处理后的 map1 和 map2 参数传递给 cv2.remap() 函数,同时指定插值方法(如 cv2.INTER_LINEAR)。
python 复制代码
remapped_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR)
  1. 显示复制后的图像:最后,我们可以通过显示函数来展示复制后的图像,以便观察结果。
python 复制代码
cv2.imshow("Remapped Image", remapped_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

通过以上步骤,我们可以利用重映射函数 cv2.remap() 来实现图像的复制。这种方法允许我们更灵活地控制图像的映射过程,以实现各种类型的图像处理效果。

5.2 翻转

5.2.1 绕着x轴

在OpenCV中,要实现图像绕x轴翻转,需要进行以下映射过程:

  1. x坐标轴的值保持不变。
  2. y坐标轴的值以x轴为对称轴进行交换。

这反映在两个映射数组(map1和map2)上的变化如下:

  • 对于map1,其值保持不变。
  • 对于map2,需要将其值调整为"总行数-1-当前行号"。

需要注意的是,在OpenCV中,行号的下标是从0开始的。因此,在对称关系中存在一个规律:"当前行号+对称行号=总行数-1"。据此,在绕着x轴翻转时,map2中当前行的行号应调整为"总行数-1-当前行号"。

5.2.2 绕y轴翻转

要实现图像绕y轴翻转,需要进行以下映射过程:

  1. y坐标轴的值保持不变。
  2. x坐标轴的值以y轴为对称轴进行交换。

这反映在两个映射数组(map1和map2)上的变化如下:

  • 对于map2,其值保持不变。
  • 对于map1,需要将其值调整为"总列数-1-当前列号"。

需要注意的是,在OpenCV中,列号的下标是从0开始的。因此,在对称关系中存在一个规律:"当前列号+对称列号=总列数-1"。据此,在绕着y轴翻转时,map1中当前列的列号应调整为"总列数-1-当前列号"。

5.2.3 绕x轴、y轴翻转

要实现图像绕x轴、y轴翻转,需要进行以下映射过程:

  1. x坐标轴的值以y轴为对称轴进行交换。
  2. y坐标轴的值以x轴为对称轴进行交换。

这反映在两个映射数组(map1和map2)上的变化如下:

  • 对于map1,需要将其值调整为"总列数-1-当前列号"。
  • 对于map2,需要将其值调整为"总行数-1-当前行号"。

5.2.4 x轴、y轴互换

要实现图像的x轴、y轴互换,需要进行以下映射过程:

对于任意一点,都需要将其x轴、y轴坐标互换。这反映在两个映射数组(mapx和mapy)上的变化如下:

  • 对于mapx,其值调整为所在行的行号。
  • 对于mapy,其值调整为所在列的列号。

需要注意的是,如果行数和列数不一致,上述运算可能存在值无法映射的情况。默认情况下,无法完成映射的值会被处理为0。

5.3 图像缩放

上述介绍的映射都是直接完成的整数映射,处理起来比较方便。在处理更复杂的问题时,

就需要对行、列值进行比较复杂的运算来实现。

相关推荐
程序猿进阶3 小时前
如何在 Visual Studio Code 中反编译具有正确行号的 Java 类?
java·ide·vscode·算法·面试·职场和发展·架构
猿饵块3 小时前
vscode
ide·vscode·编辑器
shiming88793 小时前
MATLAB图像处理
图像处理·计算机视觉·matlab
点PY5 小时前
基于Sparse Optical Flow 的Homography estimation
人工智能·opencv·计算机视觉
越甲八千5 小时前
opencv滤波算法总结
opencv
越甲八千6 小时前
opencv对比度增强方法算法汇总
人工智能·opencv·算法
独木三绝6 小时前
OpenCV第八章——腐蚀与膨胀
人工智能·opencv·计算机视觉
柠檬少少开发7 小时前
图像拼接算法及实现(一)
人工智能·算法·计算机视觉
红米煮粥7 小时前
OpenCV-直方图
人工智能·opencv·计算机视觉
隔窗听雨眠8 小时前
计算机视觉学习路线
计算机视觉