计算机视觉之几何变换(实现图片缩放、剪切、移位、镜像、仿射变换、旋转等功能)
1.图片的缩放
图片是由许多基本的像素点组成的,一般来说彩色图像中的像素点由三个数值组成,分别是蓝色分量、红色分量和绿色分量。
图片缩放分为:
- 普通的缩放,即确定下缩放后的尺寸大小,再进行缩放。
- 等比例缩放,即确定一个比例系数,长宽都乘以一个相同的比例系数,实现等比例缩放。
一般来说,图片的缩放方法有:
- 最近临域插值
- 双线性插值(默认情况)
- 像素关系重采样
- 立方插值
下面简单实现等比例缩放,用最近领域插值方法实现,测试代码如下:
1 # encoding:utf-8 2 # 基本实现步骤: 3 # 1 load 读取图片 4 # 2 info 获取图片信息 5 # 3 resize 实现图片缩放即改变图片大小 6 # 4 check 展示操作后的图像 7 import cv2 8 img = cv2.imread('image0.jpg', 1) 9 # 图片的大小 10 imgInfo = img.shape 11 print(imgInfo) 12 height = imgInfo[0] 13 width = imgInfo[1] 14 mode = imgInfo[2] # 为3 表示一个像素点由三个数值组成 15 cv2.imshow('src', img) 16 # 1 放大 缩小 17 # 2 等比例缩放 宽高比不变即为等比例缩放 18 # 等比例缩放 长宽乘以一个相同的系数 19 dstHeight = int(height*0.5) 20 dstWidth = int(width*0.5) 21 # 非等比例缩放 22 # dstHeight = 500 23 # dstWidth = 500 24 # 缩放方法:最近临域插值 双线性插值(默认情况) 像素关系重采样 立方插值 25 dst = cv2.resize(img, (dstWidth, dstHeight)) 26 cv2.imshow('image', dst) 27 cv2.waitKey(0)
运行效果如下:(src为原始图像,dst为目标图像即缩放后的图像)
原始图像:
缩放后的图像:
下面简单的说下最近临域插值的双线性插值(默认情况)的原理:
1 # 原图像src 10*20 目标图像dst 5*10 2 # src-->dst 3 # (2,4)-->(1,2) 4 # 计算公式 dst x 1 -> src x 2 newX 5 # newX=x*(src的行/dst的行) newX=1*(10/5)=2 6 # newY=y*(src的列/目标的列) newY=2*(20/10)=4 7 # 12.3 = 12 最近领域插值法 取最近的整数 8 # 9 # 双线性插值法 10 # A1=20% 上+ 80% 下 A2 11 # B1=30% 左+ 70% 右 B2 12 # 1 最终点 = A1 30% + A2 70% 13 # 2 最终点 = B1 20% + B2 80%
简单的实现下最近领域插值算法,测试代码如下:
1 # 最近临域插值算法代码实现 2 import cv2 3 import numpy as np 4 img = cv2.imread('image0.jpg', 1) 5 imgInfo = img.shape 6 height = imgInfo[0] 7 width = imgInfo[1] 8 dstHeight = int(height/3) 9 dstWidth = int(width/2) 10 dstImage = np.zeros((dstHeight, dstWidth, 3), np.uint8) # 0-255 创建一个空白模版 11 for i in range(0, dstHeight): # 行 12 for j in range(0, dstWidth): # 列 13 iNew = int(i*(height*1.0/dstHeight)) 14 jNew = int(j*(width*1.0/dstWidth)) 15 dstImage[i, j] = img[iNew, jNew] 16 cv2.imshow('dst', dstImage) 17 cv2.waitKey(0)
运行结果如下:(即展示缩放后的图像)
图像的缩放再测试,代码如下:
1 # 图片缩放 2 import cv2 3 import numpy as np 4 img = cv2.imread('image0.jpg', 1) 5 cv2.imshow('src', img) 6 imgInfo = img.shape 7 height = imgInfo[0] 8 width = imgInfo[1] 9 matScale = np.float32([[0.5, 0, 0], [0, 0.5, 0]]) 10 dst = cv2.warpAffine(img,matScale,(int(width/2),int(height/2))) 11 cv2.imshow('dst',dst) 12 cv2.waitKey(0)
运行结果如下:(src为初始图像,dst为目标图像)
src初始图像:
dst缩放后的图像:
2.图片的剪切
图片剪切的大致原理,按照我的理解就是:确定两个点,连接两个的线段即为剪切矩阵的对角线,通过这两个的坐标,就可以确定需要剪切的矩阵的方位以及矩阵大小。
更通俗一点的理解就是,你在用QQ截图的时候,总是先点一个起始点,最后再点一个终止点,最后形成一个矩阵,最后再输出这个矩阵中所有的像素值,即为剪切后的图片。
图片的剪切,测试代码如下:
1 # 实现图片的剪切 2 import cv2 3 img = cv2.imread('image0.jpg', 1) 4 cv2.imshow('src', img) 5 imgInfo = img.shape 6 # dst = img[100:500, 200:500] 7 dst = img[100:400, 100:500] # 前面是纵向的范围 后面的是横向的范围 8 cv2.imshow('image', dst) 9 cv2.waitKey(0)
运行结果如下:(src为原始图像,image为目标图像)
src原始图像:
image剪切后的图像:(剪了一朵大发发)
3.图片的移位
通过api调用实现图片的移位,测试代码如下:
1 # 通过api调用实现图片的移位 2 import cv2 3 import numpy as np 4 img = cv2.imread('image0.jpg', 1) 5 imgInfo = img.shape 6 height = imgInfo[0] 7 width = imgInfo[1] 8 img = cv2.resize(img,(int(height*0.5),int(width*0.5))) # 原始图像长宽缩小一半 9 cv2.imshow('src', img) 10 # 移位矩阵 11 matShift = np.float32([[1,0,50],[0,1,100]]) # 第一个移位矩阵 12 matShift2 = np.float32([[1,0,200],[0,1,100]]) # 第二个移位矩阵 13 # 目标矩阵 14 dst = cv2.warpAffine(img,matShift,(height,width-200)) # 第一个目标矩阵 15 dst2 = cv2.warpAffine(img,matShift2,(height,width-200)) # 第二个目标矩阵 16 # 展示两个目标图像 17 cv2.imshow('dst',dst) 18 cv2.imshow('dst2',dst2) 19 cv2.waitKey(0)
运行结果如下:(src为测试图像,dst为第一个移位后的图像,dst2为第二个移位后的图像)
src测试图像:
dst第一个移位图像:
dst2第二个移位图像:
自行实现图片向右移动100个像素,测试代码如下:
1 # 自行实现图片向右移动100个像素 2 import cv2 3 import numpy as np 4 img = cv2.imread('image0.jpg', 1) 5 img = cv2.resize(img,(int(img.shape[0]*0.5),int(img.shape[1]*0.5))) 6 cv2.imshow('src',img) 7 imgInfo = img.shape 8 height = imgInfo[0] 9 width = imgInfo[1] 10 dst = np.zeros(img.shape,np.uint8) 11 for i in range(0,height): 12 for j in range(0,width-100): 13 dst[i,j+100]=img[i,j] 14 cv2.imshow('image',dst) 15 cv2.waitKey(0)
运行结果如下:(src为原始图像,image为移位后的图像)
src原始图像:
image移位后的图像:
4.图片镜像
图像镜像的实现步骤是:
- 先创建一个最够大的画板,能够“装得下”镜像化之后的图像
- 然后再将该图像分别从前向后、从后向前绘制
- 最后绘制中心分割线
测试代码如下:
1 import cv2 2 import numpy as np 3 img = cv2.imread('image0.jpg', 1) 4 img = cv2.resize(img,(int(img.shape[0]*0.5),int(img.shape[1]*0.3))) 5 cv2.imshow('src', img) 6 imgInfo = img.shape 7 height = imgInfo[0] 8 width = imgInfo[1] 9 deep = imgInfo[2] 10 newImgInfo = (height*2, width, deep) 11 dst = np.zeros(newImgInfo, np.uint8) 12 for i in range(0, height): 13 for j in range(0, width): 14 dst[i, j] = img[i, j] 15 # x y = 2*j - y- 1 16 dst[height*2-i-1, j] = img[i, j] 17 for i in range(0, width): 18 dst[height, i] = (0, 0, 255) 19 cv2.imshow('image', dst) 20 cv2.waitKey(0)
运行结果如下:(src为初始图像,image为镜像后的图像)
src初始图像:
image镜像后的图像:
5.图片的放射变换
放射变换融合了如下几点:
- 位移
- 旋转
- 缩放
测试代码如下:
1 # 仿射变换:位移 旋转 缩放 2 import cv2 3 import numpy as np 4 img = cv2.imread('image0.jpg', 1) 5 cv2.imshow('src', img) 6 imgInfo = img.shape 7 height = imgInfo[0] 8 width = imgInfo[1] 9 # src 3->dst 3 (左上角 左下角 右上角) 10 matSrc = np.float32([[0,0],[0,height-1],[width-1,0]]) 11 matDst = np.float32([[50,50],[300,height-200],[width-300,100]]) 12 # 组合 13 matAffine = cv2.getAffineTransform(matSrc,matDst) 14 dst = cv2.warpAffine(img,matAffine,(width,height)) 15 cv2.imshow('dst',dst) 16 cv2.waitKey(0)
运行结果如下:(src为初始图像,dst为目标图像)
src初始图像:
dst目标图像:
6.图片的旋转
调用api实现图片的旋转,测试代码如下:(主要有三个参数,旋转中心的坐标、旋转角度以及缩放系数(至于为什么有缩放系数,因为旋转的时候可能会触碰到图像矩阵框的边缘,所以需要缩放处理))
1 # 图片旋转 2 import cv2 3 import numpy as np 4 img = cv2.imread('image0.jpg', 1) 5 img = cv2.resize(img,(int(img.shape[0]*0.5),int(img.shape[1]*0.5))) 6 cv2.imshow('src', img) 7 imgInfo = img.shape 8 height = imgInfo[0] 9 width = imgInfo[1] 10 # 得到旋转矩阵 center angle sc 中心点 角度 缩放系数 11 matRotate = cv2.getRotationMatrix2D((height*0.5,width*0.5),45,0.7) 12 dst = cv2.warpAffine(img,matRotate,(height,int(width*1.5))) 13 cv2.imshow('image',dst) 14 cv2.waitKey(0)
运行效果如下:(src为初始图像,image为目标图像)
src初始图像:
image目标图像:
暂时先记下这么多,还有的话再更新。。。