一、图像的介绍
- 图像以像素存储,若只有黑白颜色的三色图,为单通道,一个像素对应矩阵中的一个数字,数值为0到255。其中0表示最暗(黑色),255表示最亮(白色)。
对于RGB模式的彩色图片,为三通道图,Red、Green、Blue三原色。一个像素块对应矩阵中的一个向量,分别表示三种颜色的比例。
需要注意的是,由于历史遗留问题,opencv采用BGR模式,而不是RGB
二、图像读取保存操作(cv2)
-
图像的读取:cv2.imread(img_path,flag)
img_path: 图片的路径
flag:
cv2.IMREAD_COLOR,读取彩色图片,图片透明性会被忽略,为默认参数,也可以传入1
cv2.IMREAD_GRAYSCALE,按灰度模式读取图像,也可以传入0
cv2.IMREAD_UNCHANGED,读取图像,包括其alpha通道,也可以传入-1 -
图像的写入:cv2.imshow(window_name,img)
window_name: 指定窗口的名字
img:显示的图片对象
可以指定多个窗口名称,显示多个图片 -
图像的保存:cv2.imwrite(img_path_name,img)
img_path_name:保存的文件名
img:文件对象
# 将导入包名另命名
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 1 读取图像
img = cv.imread('messi5.jpg',0)
# 2 显示图像
# 2.1 利用opencv展示图像
cv.imshow('image',img)
# 调用cv.waitKey()给图像绘制留下时间,否则窗口会出现无响应情况,并且图像无法显示出来。
k = cv.waitKey(0)
# 3 保存图像
cv.imwrite('messigray.png',img)
用cv2读取彩色图片通道顺序为B、G、R,PIL显示图片是R、G、B顺序,因此读出来图片颜色会改变,需要对图像通道进行调序。
未调整前
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread("E:\\3.jpg")
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
调整后
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread("E:\\3.jpg")
# 调整通道顺序
# split()将img分裂为三通道
b,g,r = cv.split(img)
# merge()将三通道合并
img = cv.merge([r,g,b])
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
加入了两行代码,如下
b,g,r = cv.split(img)
img = cv.merge([r,g,b])
三、图像像素获取和编辑
- 获取像素值,更改像素值
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
# 获取(100,100)处的像素值
pixel = img[100,100]
# 将[100,100]处的像素值设置为[0,0,0]
img[100,100]=[0,0,0]
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
更改前,[100,100]处像素值为[254,174,201]
更改后,[100,100]处的像素值为[0,0,0]
- 获取[100,100]处单通道像素值,并更改单通道像素值
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
# 获取(100,100)处的像素值
pixel = img[100,100]
#获取单通道像素值
b = img[100,100,0]
g = img[100,100,1]
r = img[100,100,2]
#更改red通道值
r = img[100,100,2]=0
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
更改后[100,100]处red像素值变为0.
- 使用函数获取单通道像素值:piexl = img.item(x,y,i)
x表示横坐标,y表示纵坐标,i表示从左到右第几个元素。
此处i可选用0,1,2.从左到右分别为b通道,g通道,r通道 - 使用函数设置单通道像素值:img.itemset((x,y,i),num)
x,y,i同上。num自0~255取值,表示rgb颜色数值。
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
# 获取(100,100)处的像素值
pixel = img[100,100]
# 通过img.item()操作,可以直接定位到对应的区域。
# 即获取[100,100]处的第1个元素
piexl = img.item(100,100,0)
# itemset((x, y), z) 中的(x,y)代表的就是矩阵中元素位置,‘z’为该元素的值
img.itemset((100,100,0),99)
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
四、图片性质及截取
- List item
输出图片宽,长,通道数
import numpy as np
from PIL import Image
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
print(img.shape)
此处表示图片为宽500(rows),长500(cols),3通道(channels)
- 输出所有像素数
import numpy as np
from PIL import Image
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
print(img.size)
此处表示5005003=750000
- 输出图片数字类型
import numpy as np
from PIL import Image
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
print(img.dtype)
- ROI截取
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
#截取100行到200行,300列到400列
roi = img[100:200,300:400]
#将截取的区域roi移动到该区域
img[50:150,200:300] = roi
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
原图
移动完
截取通道
import numpy as np
from PIL import Image
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
# 截取整个蓝色通道
b = img[:,:,0]
# 截取三个通道
b,g,r = cv.split(img)
# 按照rgb重新组合
img = cv.merge((r,g,b))
# 将图片输出到屏幕
plt.imshow(img)
plt.show()
五、添加边界
- cv2.copyMakeBorder()
参数:
img:图像对象
top,bottom,left,right: 上下左右边界宽度,单位为像素值
borderType:
cv2.BORDER_CONSTANT, 带颜色的边界,需要传入另外一个颜色值
cv2.BORDER_REFLECT, 边缘元素的镜像反射做为边界
cv2.BORDER_REFLECT_101/cv2.BORDER_DEFAULT
cv2.BORDER_REPLICATE, 边缘元素的复制做为边界
CV2.BORDER_WRAP
value: borderType为cv2.BORDER_CONSTANT时,传入的边界颜色值,如[0,255,0]
六、图像的运算
- 像素算数运算
cv2.add(img1,img2,mask:None,dtype:-1)
相加的两个图片,应该有相同的大小和通道
img1:图片对象1
img2:图片对象2
mask:None (掩膜,一般用灰度图做掩膜,img1和img2相加后,和掩膜与运算,从而达到掩盖部分区域的目的)
dtype:-1
import numpy as np
from PIL import Image
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
plt.rc("font", family='Microsoft YaHei')
img1 = Image.open("E:\\3.jpg")
img2 = Image.open("E:\\4.jpg")
img1 = np.array(img1)
img2 = np.array(img2)
# cv中的加法
img3 = cv.add(img1,img2)
# 直接相加
img4 = img1+img2
# 图像显示
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img3[:,:,::-1])
axes[0].set_title("cv中的加法")
axes[1].imshow(img4[:,:,::-1])
axes[1].set_title("直接相加")
plt.show()
cv2.add(img1,img2)函数表示两个同类型的图像,对应矩阵的值相加,若大于255,则取255.
-
混合
这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。img3 = cv.addWeighted(img1,alpha,img2,beta,gamma,dtype)
参数:
img1:图片对象1
alpha:img1的权重
img2:图片对象2
beta:img1的权重
gamma:常量值,图像相加后再加上常量值
dtype:返回图像的数据类型,默认为-1,和img1一样
(img1alpha+img2beta+gamma)
import numpy as np
from PIL import Image
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
plt.rc("font", family='Microsoft YaHei')
img1 = Image.open("E:\\3.jpg")
img2 = Image.open("E:\\4.jpg")
img1 = np.array(img1)
img2 = np.array(img2)
# 2 图像混合
img3 = cv.addWeighted(img1,0.7,img2,0.3,0)
# 3 图像显示
plt.figure(figsize=(8,8))
plt.imshow(img3[:,:,::-1])
plt.show()
-
图像位运算
cv2.btwise_and(): 与运算
参数:
img1:图片对象1
img2:图片对象2
mask:掩膜cv2.bitwise_or():或运算
参数:
img1:图片对象1
img2:图片对象2
mask:掩膜cv2.bitwise_not(): 非运算
img1:图片对象1
mask:掩膜cv2.bitwise_xor():异或运算,相同为1,不同为0(11=0,10=1)
img1:图片对象1
img2:图片对象2
mask:掩膜
如何得到下方的效果:(接下来讲解步骤,详细代码请下滑)
第一步,截取操作区域
img1 = cv.imread(r"E:\4.jpg")
# 读取前景的行数与列数
rows,cols = img1.shape[0:2]
#读取背景
img2 = cv.imread(r"E:\1.jpg")
#roi中存放的为背景分割出的与前景同行同列大小的图片,从[0,0]开始
roi = img2[0:rows,0:cols]
第二步,使用cv2.cvtColor()函数将图片转成灰度图
#是RGB到gray进行颜色转换
img1_gray = cv.cvtColor(img1,cv.COLOR_BGR2GRAY)
第三步,使用二值化函数cv2.threshold()将灰度图二值化
图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。
把大于某个临界灰度值的像素灰度设为灰度极大值,把小于这个值的像素灰度设为灰度极小值,从而实现二值化。
如此处阈值为200,即小于200设置为0,大于200设置为255
#threshold()函数形式:retval,dst = cv2.threshold(src,thresh,maxval,type)
#retval:阈值(临界值)、dst:处理后的图像、src:需要处理的图像、thresh:阈值
#maxval:最大像素值、type:阈值分割类型
ret,img1_thres = cv.threshold(img1_gray,200,255,cv.THRESH_BINARY)
第四步,使用“非”操作函数cv2.bitwise_not()将上图颠倒黑白:
img1_thres_inv = cv.bitwise_not(img1_thres)
第五步,使用“与”操作函数cv2.bitwise_and()对图像掩膜(遮挡)
# 对操作区域掩膜
roi_bg = cv.add(roi,roi,mask=img1_thres_inv)
#对img1掩膜
#用灰度图做掩膜,img1与img1相加后,与淹没与运算可以达到掩盖部分区域的目的。去黑留白
img1_fg =cv.add(img1,img1,mask=img1_thres)
掩膜(mask):以图和掩膜的与运算为例:
原图中的每个像素和掩膜中的每个对应像素进行与运算。比如1 & 1 = 1;1 & 0 = 0;
比如一个3 * 3的图像与3 * 3的掩膜进行运算,得到的结果图像就是:
第六步,使用cv2.add()函数将上面两图混合(相加)
# 背景和前景相加
img_add = cv.add(img1_fg,roi_bg)
第七步,覆盖操作区域,得到最终结果
img2[0:rows,0:cols] = img_add
完整代码
#coding:utf-8
import cv2 as cv
import matplotlib.pyplot as plt
# 读取前景
img1 = cv.imread(r"E:\4.jpg")
# 读取前景的行数与列数
rows,cols = img1.shape[0:2]
# 读取背景
img2 = cv.imread(r"E:\1.jpg")
# roi中存放的为背景分割出的与前景同行同列大小的图片,从[0,0]开始
roi = img2[0:rows,0:cols]
# 是RGB到gray进行颜色转换
img1_gray = cv.cvtColor(img1,cv.COLOR_BGR2GRAY)
# threshold()函数形式:retval,dst = cv2.threshold(src,thresh,maxval,type)
# retval:阈值(临界值)、dst:处理后的图像、src:需要处理的图像、thresh:阈值
# maxval:最大像素值、type:阈值分割类型
ret,img1_thres = cv.threshold(img1_gray,200,255,cv.THRESH_BINARY)
# 用灰度图做掩膜,img1与img1相加后,与淹没与运算可以达到掩盖部分区域的目的。去黑留白
img1_fg =cv.add(img1,img1,mask=img1_thres)
# bitwise_not的作用是取反操作
img1_thres_inv = cv.bitwise_not(img1_thres)
# 拿到roi图案的背景,对操作区域掩膜
roi_bg = cv.add(roi,roi,mask=img1_thres_inv)
# 背景和前景相加
img_add = cv.add(img1_fg,roi_bg)
# 覆盖操作区域
img2[0:rows,0:cols] = img_add
# 输出图像
cv.imshow("gray",img1_gray)
cv.imshow("thres",img1_thres)
cv.imshow("fg",img1_fg)
cv.imshow("tinv",img1_thres_inv)
cv.imshow("roi_bg",roi_bg)
cv.imshow("img_add",img_add)
cv.imshow("img2",img2)
cv.waitKey(0)
cv.destroyAllWindows()
七、图像颜色空间转换,绑定trackbar到图像,中值滤波和性能评价
- 图像颜色空间转换:cv2.cvtColor(img,code)
参数:
img: 图像对象
code:
cv2.COLOR_RGB2GRAY: RGB转换到灰度模式
cv2.COLOR_RGB2HSV: RGB转换到HSV模式(hue,saturation,Value)
import cv2 as cv
img1 = cv.imread(r"E:\3.jpg")
img2=cv.cvtColor(img1,cv.COLOR_RGB2GRAY)
cv.imshow("1",img1)
cv.imshow("2",img2)
cv.waitKey(0)
cv.destroyAllWindows()
import cv2 as cv
img1 = cv.imread(r"E:\3.jpg")
img2=cv.cvtColor(img1,cv.COLOR_RGB2HSV)
cv.imshow("1",img1)
cv.imshow("2",img2)
cv.waitKey(0)
cv.destroyAllWindows()
- 实现二值化:cv2.inRange(img,lowerb,upperb)
参数:
img: 图像对象/array
lowerb: 低边界array, 如lower_blue = np.array([110,50,50])
upperb:高边界array, 如 upper_blue = np.array([130,255,255])
cv2.inRange()函数可针对多通道实行二值化,主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0),该功能类似于双阈值化操作。
import cv2 as cv
import numpy as np
img1 = cv.imread(r"E:\3.jpg")
img2 = cv.inRange(img1,np.array([50,50,50]),np.array([130,255,255]))
cv.imshow("1",img1)
cv.imshow("2",img2)
cv.waitKey(0)
cv.destroyAllWindows()
- 性能评价
cv2.getTickCount():获得时钟次数
cv2.getTickFrequency():获得时钟频率(每秒振动次数)
import cv2 as cv
img1 = cv.imread(r"E:\1.jpg")
# e1表示从一个特定的事件(开机的时刻)以后到调用此方法时刻之间的时间周期数
e1=cv.getTickCount()
# for i in range(1,5,2)表示将起始值为1,步长为2,不包含5
for i in range(5,49,2):
img2=cv.medianBlur(img1,i)
# e2表示从特定事件到调用此方法时刻之间的时间周期数
e2=cv.getTickCount()
# e2-e1则表示调用两个方法之间的时间周期数,用时间周期数/这段时间内的频率=这段时间
# t代表运行处理图片时间,t越小表示处理越快
t=(e2-e1)/cv.getTickFrequency()
print(t)
表示处理这张图片用了2.314秒
- 中值滤波:cv2.medianBlur(src, dst, kszie)
参数:
src:输入图像,Mat类的对象。该函数对通道是独立处理的,且可以处理1、3或4得到的Mat图像,但是待处理的图像深度应该是CV_8U,CV_16U,CV_32F,但是对于较大孔径尺寸的图像,只能是CV_8U。
dst:OutputArray类型的dst,目标图像,需要和输入图像有相同的尺寸和类型。
ksize:int类型ksize,孔径的线型尺寸,必须是大于1的奇数。
中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。与邻域平均法类似,但计算的是中值
函数使用中值滤波来平滑(模糊)处理一张图像
import cv2 as cv
img1 = cv.imread(r"E:\1.jpg")
img2=cv.medianBlur(img1,7)
cv.imshow('1',img1)
cv.imshow('2',img2)
k=cv.waitKey(0)
使用中值滤波前img1
使用中值滤波后img2(图像变得模糊)
-
绑定trackbar到图像-为窗口添加trackbar:cv2.createTrackbar(trackbarname,winname,value,count,onChange)
参数:
trackbarname: trackbar(轨迹栏)的名字
winname: 所属窗口的名字
value: trackbar创建时的值,即默认值
count:trackbar能设置的最大值
onChange:trackbar值发生变化时的回调函数,trackbar的值作为参数传给onchange -
绑定trackbar到图像-获取某个窗口中trackbar的值:cv2.getTrackbarPos(trackbarname,winname)
参数:
trackbarname: trackbar的名字
winname: 窗口的名字
举例:通过改变trackbar的值,来寻找最优mask范围,从而识别出图片中的蓝色五角星
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 自定义函数
# def 函数名(变量):
# 语句块
# 函数名(变量) #调用函数
# 创建回调函数
def nothing(args):
# python中pass的使用:
# 在python中有时候能看到定义一个def函数,函数内容部分填写为pass。
# 这里的pass主要作用就是占据位置,让代码整体完整。如果定义一个函数里面为空,
# 那么就会报错,当你还没想清楚函数内部内容,就可以用pass来进行填坑。
pass
img = cv.imread("e:\\5.jpg")
img_hsv = cv.cvtColor(img, cv.COLOR_RGB2HSV)
cv.namedWindow("tracks")
# 创建改变颜色的滑动条
cv.createTrackbar("LH", "tracks", 0, 255, nothing)
cv.createTrackbar("LS", "tracks", 0, 255, nothing)
cv.createTrackbar("LV", "tracks", 0, 255, nothing)
cv.createTrackbar("UH", "tracks", 255, 255, nothing)
cv.createTrackbar("US", "tracks", 255, 255, nothing)
cv.createTrackbar("UV", "tracks", 255, 255, nothing)
while (1):
# 获取八个滑动条的位置
l_h = cv.getTrackbarPos("LH", "tracks")
l_s = cv.getTrackbarPos("LS", "tracks")
l_v = cv.getTrackbarPos("LV", "tracks")
u_h = cv.getTrackbarPos("UH", "tracks")
u_s = cv.getTrackbarPos("US", "tracks")
u_v = cv.getTrackbarPos("UV", "tracks")
lower_b = np.array([l_h, l_s, l_v])
upper_b = np.array([u_h, u_s, u_v])
mask = cv.inRange(img_hsv, lower_b, upper_b)
res = cv.add(img, img, mask=mask)
cv.imshow("img", img)
cv.imshow("mask", mask)
cv.imshow("res", res)
k = cv.waitKey(1)
if k == 27:
break
cv.destroyAllWindows()
八、图像阈值化
- cv2.threshold(img,thresh,maxval,type)
参数:
img:图像对象,必须是灰度图
thresh:阈值
maxval:最大值
type:
cv2.THRESH_BINARY: 小于阈值的像素置为0,大于阈值的置为maxval
cv2.THRESH_BINARY_INV: 小于阈值的像素置为maxval,大于阈值的置为0
cv2.THRESH_TRUNC: 小于阈值的像素不变,大于阈值的置为thresh
cv2.THRESH_TOZERO 小于阈值的像素置0,大于阈值的不变
cv2.THRESH_TOZERO_INV 小于阈值的不变,大于阈值的像素置0
返回两个值
ret:阈值
img:阈值化处理后的图像
cv2.threshold(img,thresh,maxval,type):将一个灰色的图片,变成要么是白色要么就是黑色。(大于规定thresh值就是设置的最大值(常为255,也就是白色))
- cv2.adaptiveThreshold(img,maxValue,adaptiveMethod,threshType,blocksize,C)
参数:
img: 图像对象,8-bit单通道图
maxValue:最大值
adaptiveMethod: 自适应方法
cv2.ADAPTIVE_THRESH_MEAN_C :阈值为周围像素的平均值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C : 阈值为周围像素的高斯均值(按权重)
threshType:
cv2.THRESH_BINARY: 小于阈值的像素置为0,大于阈值的置为maxValuel
cv2.THRESH_BINARY_INV: 小于阈值的像素置为maxValue,大于阈值的置为0
blocksize: 计算阈值时,自适应的窗口大小,必须为奇数 (如3:表示附近3个像素范围内的像素点,进行计算阈值)
C: 常数值,通过自适应方法计算的值,减去该常数值
cv2.adaptiveThreshold:把图片每个像素点作为中心取N*N的区域,然后计算这个区域的阈值,来决定这个像素点变0还是变255
#coding:utf-8
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(r"e:\1.jpg",0)
# 图像的二值化
# 小于127的灰度值设置为0,大于127,小于255的灰度值设置为255.
ret,thre1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# 将图片每个像素点作为中心,取7*7的区域,计算该区域的阈值,每个区域计算出的阈值的基础上在减去2作为这个区域的最终
# 阈值,通过ADAPTIVE_THRESH_MEAN_C算法,将满足条件的像素值变为255.
adaptive_thre1 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,7,2)
# 同理,不过使用的是ADAPTIVE_THRESH_GAUSSIAN_C算法
adaptive_thre2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,7,2)
titles = ["img","thre1","adaptive_thre1","adaptive_thre2"]
imgs = [img,thre1,adaptive_thre1,adaptive_thre2 ]
for i in range(4):
plt.subplot(2,2,i+1), plt.imshow(imgs[i],"gray")
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
- 奥斯二值化
对于一些双峰图像,奥斯二值化能找到两峰之间的像素值作为阈值,并将其返回。适用于双峰图像的阈值化,或者通过去噪而产生的双峰图像。
注: 双峰图像,顾名思义,灰度级直方图呈明显的双峰状的图像
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('e:\\1.jpg',0)
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in range(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()
九、图像形状变换
- 图像缩放:cv2.resize(src,dsize,fx,fy,interpolation)
参数:
src: 输入图像对象
dsize:输出矩阵/图像的大小,为0时计算方式如下:dsize = Size(round(fxsrc.cols),round(fysrc.rows))
fx: 水平轴的缩放因子,为0时计算方式: (double)dsize.width/src.cols
fy: 垂直轴的缩放因子,为0时计算方式: (double)dsize.heigh/src.rows
interpolation:插值算法
cv2.INTER_NEAREST : 最近邻插值法
cv2.INTER_LINEAR 默认值,双线性插值法
cv2.INTER_AREA 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image
decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
cv2.INTER_CUBIC 基于4x4像素邻域的3次插值法
cv2.INTER_LANCZOS4 基于8x8像素邻域的Lanczos插值
import cv2
img = cv2.imread(r'e:\3.jpg')
# 水平轴与垂直轴各放大两倍
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)
cv2.imshow("1",img)
cv2.imshow("2",res)
cv2.waitKey(0)
- 仿射变换:cv2.warpAffine(img,M,dsize,flags,borderMode,borderValue)
参数:
img: 图像对象
M:23 transformation matrix (转变矩阵)
dsize:输出矩阵的大小,注意格式为(cols,rows) 即width对应cols,height对应rows
flags:可选,插值算法标识符,有默认值INTER_LINEAR,
如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转dst(x,y)=src(M11x+M12y+M13,M21x+M22*y+M23)
borderMode:可选, 边界像素模式,有默认值BORDER_CONSTANT
borderValue:可选,边界取值,有默认值Scalar()即0
仿射变换的M表示平移,缩放,翻转,旋转和剪切的一系列操作。如9.4
import cv2
import numpy as np
img = cv2.imread(r'e:\3.jpg')
height, width = img.shape[:2]
# 在原图像和目标图像上各选择三个点
mat_src = np.float32([[0, 0],[0, height-1],[width-1, 0]])
mat_dst = np.float32([[0, 0],[100, height-100],[width-100, 100]])
# 得到变换矩阵
mat_trans = cv2.getAffineTransform(mat_src, mat_dst)
# 进行仿射变换
dst = cv2.warpAffine(img, mat_trans, (width,height))
# 显示
imgs = np.hstack([img,dst])
cv2.namedWindow('imgs', cv2.WINDOW_NORMAL)
cv2.imshow("imgs",imgs)
cv2.waitKey(0)
- 平移变换
import cv2
import numpy as np
img = cv2.imread(r'e:\3.jpg')
rows,cols = img.shape[:2]
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',dst)
cv2.waitKey(0)
- 旋转变换:getRotationMatrix2D(center,angle,scale)
import cv2
img = cv2.imread(r'e:\3.jpg')
rows,cols = img.shape[:2]
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 1)
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',dst)
cv2.waitKey(0)
- 仿射变换矩阵的计算
import cv2
import numpy as np
img = cv2.imread(r'e:\3.jpg')
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))
cv2.imshow("1",img)
cv2.imshow("2",dst)
cv2.waitKey(0)
- 透视变换:cv2.warpPerspective(src,M,dsize,flags,borderMode,borderValue)
参数:
src: 图像对象
M:33 transformation matrix (转变矩阵)
dsize:输出矩阵的大小,注意格式为(cols,rows) 即width对应cols,height对应rows
flags:可选,插值算法标识符,有默认值INTER_LINEAR,
如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转dst(x,y)=src(M11x+M12y+M13,M21x+M22*y+M23)
borderMode:可选, 边界像素模式,有默认值BORDER_CONSTANT
borderValue:可选,边界取值,有默认值Scalar()即0
仿射变换都是在二维空间的变换,透视变换(投影变换)是在三维空间中发生了旋转。需要前后四组坐标来计算对应的转变矩阵
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(r'e:\3.jpg')
rows,cols,ch = img.shape
b,g,r=cv2.split(img)
img=cv2.merge([r,g,b])
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(122),plt.imshow(dst),plt.title('Output')
plt.show()
- 透视变换:cv2.getPerspectiveTransform(src,dst)
参数:
src:原图像中的四组坐标,如 np.float32([[56,65],[368,52],[28,387],[389,390]])
dst: 转换后的对应四组坐标,如np.float32([[0,0],[300,0],[0,300],[300,300]])