图像的读取: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]
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()
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()
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)
import numpy as np
from PIL import Image
# 读取图像
img = Image.open("E:\\3.jpg")
# 导入数组
img = np.array(img)
print(img.dtype)
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()
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()
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()函数可针对多通道实行二值化,主要是将在两个阈值内的像素值设置为白色(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()
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)
中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。与邻域平均法类似,但计算的是中值
函数使用中值滤波来平滑(模糊)处理一张图像
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):将一个灰色的图片,变成要么是白色要么就是黑色。(大于规定thresh值就是设置的最大值(常为255,也就是白色))
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.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)
仿射变换的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)
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)
仿射变换都是在二维空间的变换,透视变换(投影变换)是在三维空间中发生了旋转。需要前后四组坐标来计算对应的转变矩阵
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()