图像的几何变化


一、基本概念

在不改变图像的内容的前提下, 对图像的像素进行空间几何变化;
包括 图像的平移、镜像变换、缩放和旋转等;
假设原始图像的 f(x0, y0),经过几何变化产生的目标图像为 g(x1, y1), 则空间变换(映射)关系为:

x1 = s(x0, y0)
y1 = t(x0, y0)

那么, s(x0, y0), t(x0, y0) 为由 f(x0, y0) 到 g(x1, y1) 的坐标变换函数;

求解出坐标变换函数后,开始计算变换后的图像的像素为止,然后插值到变换后的图像上。


二、插值法

对于数字图像而言,像素的坐标是 离散型非负整数;在进行控件坐标转换的时候,可能会产生浮点坐标;
例如 (11, 11) --> (5.5, 5.5), 这种坐标值是无效的,插值法就是用来处理这些浮点数的;
常见的插值法:
1、最邻近插值法
2、双线性插值法
3、二次立方插值法;
4、三次立方插值法等


最邻近插值法

假设 u,v 是 0<u, v<1 的小数,(i+u, j+v)为输入的像素坐标,待求的像素灰度值 f(i+u, j+v), 根据 u,v 的值不同, f(i+u, j+v) 的值也是不同的;

弊端:最近邻的计算量很小,但是会造成图像灰度上的不连续;在灰度变化密集的时候,会有锯齿的情况。


双线性插值法

对于目标像素,设置坐标通过反向变换得到浮点坐标 (i+u, j+v);
其中 i, j 都是非负整数;u,v 是 [0,1) 区间的浮点数; 这个像素的值 f(i+u, j+v) 由原图坐标 (i,j), (i+1,j), (i, j+1), (i+1, j+1) 所对应的周围4个像素值决定。

相比最近邻插值法,双线性的计算量很大,但是缩放之后的图像质量高,不会出现像素值不连续的情况。
双线性插值法 具有 低通过滤器的特性,算是图像的高频分量,图像在轮廓上会变得模糊;


差值算法的实现

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('lena.jpg')
# 封装方法来显示图片
def cv_show(img):
    cv2.imshow('w title',img) 
    waitret = cv2.waitKey(2000) 
    # wait = cv2.waitKey()
    print(waitret)
    cv2.destroyAllWindows()

resize

resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst

  1. 默认差值算法为双线性插值;
  2. src:输入图像;
  3. 返回:输出图像
  4. dsize:输出图像的大小;如果当前参数为0,原始图像缩放的大小需要按照公式进行计算:dsize = Size(round(fx * src.cols), round(fy * src.rows))。fx 和 fy 是宽度和高度的缩放比例。
  5. interpolation 表示差值的方式
cv2.resize()
 
img.shape
# (263, 263, 3)

三、图像的缩放

分为 水平缩放系数 和 垂直缩放系数;

  • < 1 变小
  • = 1 不变
  • > 1 变大

缩放原理

$ x = x_0 * fx ( ) y = y_0 * fy $

  • fx : 水平缩放系数
  • fy : 垂直缩放系数
  • $ (x_0, y_0) $ : 缩放之前的坐标
  • (x, y) : 缩放之后的坐标

img1 = cv2.resize(img, (120, 120))
plt.imshow(img1)

output_14_1.png

img2 = cv2.resize(img, (500, 500))
plt.imshow(img)

output_15_1.png

img3 = cv2.resize(img, (500, 500), interpolation=cv2.INTER_LINEAR)
plt.imshow(img3)

output_17_1.png


四、图像的平移

warpAffine 方法

warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) -> dst
. @brief Applies an affine transformation to an image.

  • 插补方法的标志组合(见#InterpolationFlags) 和可选的标志 #WARP_INVERSE_MAP,这意味着M是逆变换 (( exttt{dst} ightarrow exttt{src}))

  • borderMode 像素外推方法(见#BorderTypes);当borderMode=#BORDER_TRANSPARENT时,它意味着目标图像中对应于源图像中的“异常值”的像素不被函数修改。


调用

cv2.warpAffine
arr1 = np.array([[1,0, 100], [0,1,100]], np.float32)
img4 = cv2.warpAffine(img, arr1, img.shape[:2])

五、图像的旋转

让图像按照某一点旋转到指定的角度,图像旋转之后不会变形,但是垂直对称轴和水平对称轴 会发生改变,旋转后的坐标 和 原始图像的坐标已经不能通过简单地加减乘除来得到映射;

确定参数:图像的旋转中心,旋转角度,缩放因子;

步骤:

  1. 得到变换矩阵
  2. 通过函数进行变换

注意:

  1. 无论是平移还是旋转,都会出现图像被裁剪的问题(比如旋转 75°的时候);
    因此需要先计算输出图像的尺寸,来避免数据的损失。

getRotationMatrix2D 方法

getRotationMatrix2D(center, angle, scale) -> retval
. @brief Calculates an affine matrix of 2D rotation.

这个方法计算了下面的矩阵

[egin{bmatrix} alpha & eta & (1- alpha ) cdot exttt{center.x} - eta cdot exttt{center.y} \ - eta & alpha & eta cdot exttt{center.x} + (1- alpha ) cdot exttt{center.y} end{bmatrix} ]

[[egin{array}{l} alpha = exttt{scale} cdot cos exttt{angle} , \ eta = exttt{scale} cdot sin exttt{angle} end{array} ]

这个变换将旋转中心映射到它自己。如果这不是目标,调整转换。

  • center:原始图片的旋转中心 Center of the rotation in the source image.
  • angle :旋转角度。正值表示逆时针旋转(假设坐标原点为左上角)。
  • scale :各向同性的比例因子。
h,w,n = img.shape
 
mat = cv2.getRotationMatrix2D((w/2, h/2), -90,1)
img5 = cv2.warpAffine(img, mat, img.shape[:2])  # img.shape[:2] 取图片的宽高
plt.imshow(img5)

output_27_1.png


mat = cv2.getRotationMatrix2D((w/2, h/2), -135,1)
img6 = cv2.warpAffine(img, mat, (int(img.shape[0]*1.5), int(img.shape[1]*1.6)) 
 
img.shape[0] * 1.5  # 394.5
 
int(img.shape[1]*1.6)  #  420

六、镜像变换

理论

分为 水平镜像和垂直镜像

水平镜像以 图像垂直中线 为轴;

垂直镜像以 水平中线为轴,将图像的上半部分和下半部分对调


变换原理

水平镜像 $ x = width - x, y = y_0 $

垂直镜像 $ x = x_0, y = height - y_0 $


flip 函数

flip(src, flipCode[, dst]) -> dst

  • flipCode : 如何反转数组
    • 0 垂直反转
    • 1 水平翻转
    • 负数(如-1),同时翻转

. @sa transpose , repeat , completeSymm


使用

img6 = cv2.flip(img,0)
plt.imshow(img6)

output_33_1.png

原文地址:https://www.cnblogs.com/fldev/p/14371246.html