计算机视觉—图片几何变换(2)
几何变换不改变图像的像素值,只是在图像平面上进行像素的重新安排。适当的几何变换可以最大程度地消除由于成像角度、透视关系乃至镜头自身原因所造成的几何失真所产生的负面影响。几何变换常常作为图像处理应用的预处理步骤, 是图像归一化的核心工作之一。
一个几何变换需要两部分运算:首先是空间变换所需的运算,如平移、缩放、旋转和正平行投影等,需要用它来表示输出图像与输入图像之间的(像素)映射关系;此外,还需要使用灰度插值算法, 因为按照这种变换关系进行计算, 输出图像的像素可能被映射到输入图像的非整数坐标上。
一、图片剪切
import cv2
img = cv2.imread('image0.jpg',1)
imgInfo = img.shape
dst = img[100:200,100:300]
# 从X轴的100px到200px,y轴的100px到300px
cv2.imshow('image',img)
# 剪切前
cv2.imshow('image',dst)
# 剪切后
cv2.waitKey(0)
结果

二、图片移位
1、图片移位的数学原理
x,y是图片最终的坐标(x,y),x0,y0是图片原始坐标,∆x,∆y图片平移的大小,公式如下:

变换成矩阵如下:

2、opencv的实现方法
函数warpAffine使用指定的矩阵转换源图像:
𝚍𝚜𝚝(X,y )= 𝚜𝚛𝚌(𝙼11X+ 𝙼12y + 𝙼13,𝙼21X+ 𝙼22y + 𝙼23)
cv2.warpAffine(src,M,dsize[,dst[,flags[,borderMode[,borderValue]]]])
参数:
- SRC 输入图像。
- DST 输出具有dsize大小和src相同类型的图像。 中号 2 × 3 变换矩阵。
- DSIZE 输出图像的大小。
- flags 插值方法的组合和可选标志WARP_INVERSE_MAP,这意味着M是逆变换(𝚍𝚜𝚝 → 𝚜𝚛𝚌 )。
- borderMode 像素外插法; 当borderMode = BORDER_TRANSPARENT时,这意味着目标图像中与源图像中的“离群值”相对应的像素不会被该函数修改。
- borderValue 在边界不变的情况下使用的值; 默认情况下,它是0。
import cv2
import numpy as np
img = cv2.imread('image0.jpg',1)
cv2.imshow('src',img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
matShift = np.float32([[1,0,100],[0,1,200]])
dst = cv2.warpAffine(img,matShift,(height,width))
cv2.imshow('dst',dst)
# 平移图片
cv2.waitKey(0)
结果:

3、python的实现方法
import cv2
import numpy as np
img = cv2.imread('image0.jpg',1)
cv2.imshow('src',img)
imgInfo = img.shape
dst = np.zeros(img.shape,np.uint8)
height = imgInfo[0]
width = imgInfo[1]
for i in range(0,height):
for j in range(0,width-100):
dst[i,j+100]=img[i,j]
cv2.imshow('image',dst)
cv2.waitKey(0)
三、图片缩放
在计算机中,图像是以矩阵的形式保存的,先行后列。 所以,一张宽×高×颜色通道=480×256×3 的图片会保存在一个 256×480×3 的三维张量中。图像处理时也是按照这种思想进行计算的(其中就包括 OpenCV 下的图像处理),即 高×宽×颜色通道。
1、图片缩放的数学原理
warpAffine()实现缩放,矩阵公式如下。

2、opencv的实现方法
cv2.resize()可以实现图片的缩放,但是cv2.resize这个api却是个小例外。因为它的参数输入却是 宽×高×颜色通道
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
参数:
- src - 原图
- dst - 目标图像。当参数dsize不为0时,dst的大小为size;否则,它的大小需要根据src的大小,参数fx和fy决定。dst的类型(type)和src图像相同
- dsize - 目标图像大小。 当dsize为0时,它可以通过以下公式计算得出: dsize = Size(round(fxsrc.cols) round(fysrc.rows)) 所以,参数dsize和参数(fx, fy)不能够同时为0
- fx - 水平轴上的比例因子。当它为0时,计算公式如下: (double) dsize.width/src.cols
- fy - 垂直轴上的比例因子。当它为0时,计算公式如下: (double) dsize.width/src.cols
- interpolation - 插值方法。共有5种:
- INTER_NEAREST - 最近邻插值法
- INTER_LINEAR - 双线性插值法(默认)
- INTER_AREA - 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
- INTER_CUBIC - 基于4x4像素邻域的3次插值法
- INTER_LANCZOS4 - 基于8x8像素邻域的Lanczos插值
差值方法原理介绍:https://blog.csdn.net/chaipp0607/article/details/65658736
# 1 load 2 info 3 resize 4 check
import cv2
img = cv2.imread('image0.jpg',1)
imgInfo = img.shape
print(imgInfo)
height = imgInfo[0]
width = imgInfo[1]
mode = imgInfo[2]
# 1 放大 缩小 2 等比例 非 2:3
dstHeight = int(height*0.5)
dstWidth = int(width*0.5)
#最近临域插值 双线性插值 像素关系重采样 立方插值
dst = cv2.resize(img,(dstWidth,dstHeight))
cv2.imshow('image',dst)
matScale = np.float32([[0.5,0,0],[0,0.7,0]])
dst = cv2.warpAffine(img,matScale,(int(width*0.5),int(height*0.7)))
cv2.imshow('dst2',dst2)
# 图片宽*0.5,高*0.7
cv2.waitKey(0)
结果:
(547, 730, 3)
3、python的实现方法
import cv2
import numpy as np
img = cv2.imread('image0.jpg',1)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
dstHeight = int(height/2)
dstWidth = int(width/2)
dstImage = np.zeros((dstHeight,dstWidth,3),np.uint8)#0-255
for i in range(0,dstHeight):#行
for j in range(0,dstWidth):#列
iNew = int(i*(height*1.0/dstHeight))
jNew = int(j*(width*1.0/dstWidth))
dstImage[i,j] = img[iNew,jNew]
cv2.imshow('dst',dstImage)
cv2.waitKey(0)
四、图片镜像
1、图片镜像的数学原理
(1)垂直翻转原理

(2)水平翻转原理

(3)180度翻转原理

2、opencv的实现方法
import cv2
import numpy as np
img = cv2.imread('canton02.jpg',1)
cv2.imshow('src',img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
deep = imgInfo[2]
newImgInfo = (height*2,width,deep)
newImgInfo2 = (height,width*2,deep)
newImgInfo3 = (height*2,width*2,deep)
dst = np.zeros(newImgInfo,np.uint8)
# 垂直翻转
cv2.imshow('dst',dst)
for i in range(0,height):
for j in range(0,width):
dst[i,j] = img[i,j]
# x , y=2*h-y-1
dst[height*2-i-1,j] = img[i,j]
cv2.imshow('dst',dst)
# 水平翻转
dst2 = np.zeros(newImgInfo2,np.uint8)
for i in range(0,height):
for j in range(0,width):
dst2[i,j] = img[i,j]
# x=2*w-x-1 , y
dst2[i,width*2-j-1] = img[i,j]
cv2.imshow('dst2',dst2)
# 水平垂直都翻转
dst3 = np.zeros(newImgInfo3,np.uint8)
for i in range(0,height):
for j in range(0,width):
dst3[i,j] = img[i,j]
# x=2*w-x-1 , y=2*h-y-1
dst3[height*2-i-1,width*2-j-1] = img[i,j]
cv2.imshow('dst3',dst3)
cv2.waitKey(0)
四、图片转换
1、图片旋转的数学原理

如上图,r是点到原点的固定距离,角θ是点的原始角度位置与水平线的夹角,θ是旋转角。坐标表示

在极坐标系中,点的原始坐标为

变换方程为:

变换成矩阵:

2、opencv的实现方法
cv2.getRotationMatrix2D函数
图像先绕坐标原点旋转,旋转之后图像的中心点到了另一个位置。

旋转前后图像的中心点就不在一个位置了,为了让它们在一个位置上,需要再平移图像。

图像中心点旋转后的坐标减去旋转前的坐标就是转换矩阵中的平移向量了。
getRotationMatrix2D (Point2f center,double angle,double scale)
参数:
- center 源图像中的旋转中心
- angle 旋转角度(度)。正值表示逆时针旋转(坐标原点被认为是左上角)
- scale 各向同性的比例因子。
import cv2
import numpy as np
img = cv2.imread('canton02.jpg',1)
cv2.imshow('src',img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 2*3
matRotate = cv2.getRotationMatrix2D((height*0.5,width*0.5),45,1)# mat rotate 1 center 2 angle 3 scale
#100*100 25
dst = cv2.warpAffine(img,matRotate,(height,width))
cv2.imshow('dst',dst)
cv2.waitKey(0)
五、图片仿射变换
1、图片仿射变换的数学原理
先看一个动图,直观的了解一些什么是仿射变换,

仿射变换:一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移).
我们能够用仿射变换来表示:
- 旋转 (线性变换)
- 平移 (向量加)
- 缩放操作 (线性变换)
仿射变换是一种二维坐标(x0, y0)到二维坐标(x,y)的线性变换,其数学表达式形式如下:

对应的齐次坐标矩阵表示形式为:

图像处理中,可应用仿射变换对二维图像进行平移、缩放、旋转等操作,具体参考上面几节。

2、opencv的实现方法
getAffineTransform(InputArray src,InputArray DST)
参数:
- InputArray src: 表示输入的三个点
- InputArray dstL: 表示输出的三个点
import cv2
import numpy as np
img = cv2.imread('image0.jpg',1)
cv2.imshow('src',img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
#src 3->dst 3 (左上角 左下角 右上角)
matSrc = np.float32([[0,0],[0,height-1],[width-1,0]])
matDst = np.float32([[50,50],[300,height-200],[width-300,100]])
#组合
matAffine = cv2.getAffineTransform(matSrc,matDst)# mat 1 src 2 dst
dst = cv2.warpAffine(img,matAffine,(width,height))
cv2.imshow('dst',dst)
cv2.waitKey(0)
转载自:https://juejin.cn/post/6844903608475992072