OpenCV-Python(14):图像几何变换

发布时间:2023年12月25日

背景说明

????????图像几何变换是计算机视觉和图像处理领域中的重要技术。它通过对图像进行平移、旋转、缩放、翻转等操作,改变图像的大小、位置或方向,以实现对图像的变换和处理。

????????图像几何变换在很多应用中都有广泛的应用,例如:

  1. 视觉定位和导航:通过对图像进行平移、旋转和缩放等变换,可以实现机器人的视觉定位和导航。例如,可以通过将机器人的摄像头图像与地图图像进行匹配,来确定机器人的位置和方向。
  2. 图像配准:通过对图像进行平移、旋转和缩放等变换,可以将不同视角或不同时间拍摄的图像进行配准,以实现图像的对齐和融合。例如,在医学影像中,可以将不同扫描时间的MRI图像进行配准,以便进行病变的比较和分析。
  3. 目标检测和跟踪:通过对图像进行平移、旋转和缩放等变换,可以实现目标的检测和跟踪。例如,可以通过对图像进行缩放和平移,将目标物体的尺寸和位置进行标准化,以便在不同场景下进行准确的目标检测和跟踪。
  4. 图像增强和修复:通过对图像进行平移、旋转和缩放等变换,可以实现图像的增强和修复。例如,可以通过对图像进行缩放和旋转,将图像中的噪声和失真进行降低,以获得更清晰和更准确的图像。

????????图像几何变换的实现通常基于线性代数和几何学的原理。在实际应用中,可以使用各种图像处理库和工具,如OpenCV、numpy和scikit-image等,来实现图像几何变换操作。这些工具提供了丰富的函数和算法,使得图像几何变换变得简单和高效。

学习目标

  • 学习对图像进行各种几个变换,例如移动、旋转、仿射变换等。
  • 学习函数有cv2.getPerspectiveTransform、cv2.warpAffine和cv2.warpPersperctive

变换函数

????????OpenCV提供了两个转换函数,cv.warpAffine和cv.warpPerspective,可以用它们实现各种类型的变换。cv2.warpAffine() 采用 2x3 变换矩阵作为输入;cv2.warpPerspective ()采用 3x3 变换矩阵作为输入。

cv2.warpAffine()函数是用于执行图像几何变换的函数之一,返回值为输出图像,语法如下:

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

参数说明:

  • src:输入图像,可以是灰度图像或彩色图像。
  • M:2x3 变换矩阵,用于指定要执行的变换操作。可以通过函数 cv2.getRotationMatrix2D() 或 cv2.getAffineTransform() 来获取变换矩阵。
  • dsize:输出图像的大小,可以是指定的元组 (width, height),也可以直接传入输出图像的宽度和高度。
  • dst:可选参数,输出图像,与输入图像具有相同的类型和大小。
  • flags:可选参数,用于指定插值方法,默认为 cv2.INTER_LINEAR,可以选择 cv2.INTER_NEAREST、cv2.INTER_LINEAR、cv2.INTER_CUBIC 等。
  • borderMode:可选参数,用于指定边界像素的处理方式,默认为 cv2.BORDER_CONSTANT,可以选择 cv2.BORDER_CONSTANT、cv2.BORDER_REPLICATE、cv2.BORDER_REFLECT 等。
  • borderValue:可选参数,用于指定边界像素的默认值,默认为 0。

cv2.warpPerspective()?是 OpenCV 中用于执行透视变换的函数之一,函数的返回值为输出图像。它可以根据用户指定的变换矩阵对图像进行透视变换。函数的语法如下:

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

参数说明:

  • src:输入图像,可以是灰度图像或彩色图像。
  • M:3x3 变换矩阵,用于指定要执行的透视变换操作。可以通过函数 cv2.getPerspectiveTransform() 来获取变换矩阵。
  • dsize:输出图像的大小,可以是指定的元组 (width, height),也可以直接传入输出图像的宽度和高度。
  • dst:可选参数,输出图像,与输入图像具有相同的类型和大小。
  • flags:可选参数,用于指定插值方法,默认为 cv2.INTER_LINEAR,可以选择 cv2.INTER_NEAREST、cv2.INTER_LINEAR、cv2.INTER_CUBIC 等。
  • borderMode:可选参数,用于指定边界像素的处理方式,默认为 cv2.BORDER_CONSTANT,可以选择 cv2.BORDER_CONSTANT、cv2.BORDER_REPLICATE、cv2.BORDER_REFLECT 等。
  • borderValue:可选参数,用于指定边界像素的默认值,默认为 0。

扩展缩放(缩放变换)

????????扩展缩放只是改变图像的尺寸大小。OpenCV 提供的函数cv2.resize()可以实现这个功能。图像的尺寸可以自己手动设置,也可以指定缩放因子。我们可以选择使用不同的插值方法。在缩放时推荐用cv2.INTER_AREA,扩展时推荐使用cv2.INTER_CUBIC(慢))和v2.INTER_LINEAR。默认情况下所有改变图像尺寸大小的操作使用的插值方法都是cv2.INTER_LINEAR。你可以使用下任意一种方法改变图像的尺寸。

cv2.resize()函数的返回值为输出图像,语法如下:

cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])

参数说明:

  • src:输入图像,可以是灰度图像或彩色图像。
  • dsize:输出图像的大小,可以是指定的元组 (width, height),也可以直接传入输出图像的宽度和高度。
  • dst:可选参数,输出图像,与输入图像具有相同的类型和大小。
  • fx:可选参数,x 轴方向的缩放比例,默认为 0。如果设置为 0,表示根据 dsize 来计算缩放比例。
  • fy:可选参数,y 轴方向的缩放比例,默认为 0。如果设置为 0,表示根据 dsize 来计算缩放比例。
  • interpolation:可选参数,用于指定插值方法,默认为 cv2.INTER_LINEAR,可以选择 cv2.INTER_NEAREST、cv2.INTER_LINEAR、cv2.INTER_CUBIC 等。
import cv2
import numpy as np
img=cv2.imread('messi5.jpg')
# 下面的None 本应是输出图像的尺寸,但是因为后面我们设置了缩放因子
# 因此这里为None
res=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
#OR
# 这里呢我们直接设置输出图像的尺寸,所以不用设置缩放因子
height,width=img.shape[:2]
res=cv2.resize(img,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
while(1):
cv2.imshow('res',res)
cv2.imshow('img',img)
if cv2.waitKey(1) & 0xFF == 27:
    break
cv2.destroyAllWindows()

常见的插值算法:

INTER_NEAREST 最近邻插值
INTER_LINEAR 双线性插值
INTER_CUBIC 双三次插值
INTER_AREA 使用像素面积关系进行重采样。它可能是图像抽取的首选方法,因为它可以提供无摩尔纹的结果。但是当图像缩放时,它类似于INTER_NEAREST方法。.
INTER_LANCZOS4 8x8邻域上的兰索斯插值
INTER_LINEAR_EXACT 位精确双线性插值
INTER_NEAREST_EXACT 位精确最近邻插值。这将产生与PIL,scikit-image或Matlab中的最近邻方法相同的结果.
INTER_MAX 插值码的掩码

平移变换

????????平移是对象位置的移动。如果您知道 (x,y) 方向的偏移量(tx,ty),可以创建转换矩阵M如下:

需要使用numpy数组构建这个矩阵,把它变成一个数据类型为 np.float32 的 Numpy 数组,并传递给 cv.warpAffine()函数。?M = np.float32([[1,0,tx],[0,1,ty]]),看看下面这个例子吧,它被移动了
(100,50)个像素。

?

import numpy as np
import cv2 

img = cv2.imread('../Resources/msser.jpg')
rows,cols,_ = img.shape
M = np.float32([[1,0,100],[0,1,50]])
# dst(x,y)=src(1x+0y+100, 0x+1y+50)=src(x+100,y+50)
dst = cv2.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()

如果更改转换矩阵M,还可以实现各种变换操作当 M = np.float32([[-1,0,cols],[0,-1,rows]])
可以实现图像XY方向的翻转。

警告:函数cv2.warpAffine() 的第三个参数的是输出图像的大小,它的格式应该是图像的宽、高。应记住的是图像的宽对应的是列数高对应的是行数。

旋转变换

对一个图像旋转角度θ,需要使用下面的旋转矩阵:

M = np.float32([[cos θ, -sin θ],[sin θ, cos θ]]),但OpenCV允许在任意地方进行旋转,所以旋转矩阵应该为

即,M = np.float32([[α, β, (1-α).center_x - β.center_y],[-β, α, β.center_x + (1-α).center_y]])
其中α = scale · cos θ, ? β = scale · sin θ,为更方便地构建旋转矩阵,OpenCV提供了一个旋转矩阵构建函数cv2.getRotationMatrix2D。下面的例子是在不缩放的情况下将图像旋转?90 度。

import cv2
import numpy as np
img=cv2.imread('messi5.jpg',0)
rows,cols=img.shape
# 第一个参数为旋中心,第二个为旋转角度,第三个为旋转后的缩放因子
# 可以通过设置旋转中心、缩放因子以及窗口大小来防止旋转后超出边界的问题
M=cv2.getRotationMatrix2D((cols/2,rows/2),45,0.6)
# 第三个参数是输出图像的尺寸中心
dst=cv2.warpAffine(img,M,(2*cols,2*rows))
while(1):
    cv2.imshow('img',dst)
    if cv2.waitKey(1)&0xFF==27:
        break
cv2.destroyAllWindows()

?

仿射变换

????????在仿射变换中,原图中所有平行线在结果图像中同样平行。为创建这个矩阵,需要从原图像中找到三个点以及他们在输出图像中的位置,然后cv2.getAffineTransForm()会创建一个2X3的矩阵。最后这个矩阵会被传给函数cv2.warpAffine()。来看看下面的例子以及我选择的点,标记为绿色的点。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img=cv2.imread('drawing.png')
rows,cols,ch=img.shape

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))

plt.subplot(121,plt.imshow(img),plt.title('Input'))
plt.subplot(121,plt.imshow(img),plt.title('Output'))
plt.show()

?

透视变换

????????对于透视变换,我们需要一个3x3转换矩阵。在变换前后直线还是直线。要构建这个变换矩阵,需要在原图上找到4个点,以及他们在输出图上对应的位置,这四个点中任意三个都不能共线,这个变换矩阵可以通过函数cv2.getPerspectiveTransform()构建,然后这个矩阵传给函数v2.warpPerspective()。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img=cv2.imread('sudokusmall.png')
rows,cols,ch=img.shape

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))

plt.subplot(121,plt.imshow(img),plt.title('Input'))
plt.subplot(121,plt.imshow(img),plt.title('Output'))
plt.show()

文章来源:https://blog.csdn.net/mzl_18353516147/article/details/135198229
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。