目录
基于对学校所学课程的完善和补充(老师摆大烂),在寒假决定自学opencv,将学习过程以笔记形式上传至csdn方便以后复习。学习过程主要参考唐宇迪老师的opencv实战课程,此笔记参考网络相关资料,因为opencv方面属于新手,若有错误或者不妥的地方欢迎指出。
学习使用的实验环境是python3.6+opencv3.4.1,在jupyter notebook上进行的实验。
首先导入所需的库:
import cv2
import matplotlib.pyplot as plt
import numpy as np
#%matplotlib inline
1.图像的读取和显示
图像的读取:
使用imread函数,括号内可指定同一文件夹下的文件或者直接指定文件的绝对路径。
#图像的读取,使用imread函数
img=cv2.imread('C:/photo/happy.jpg')
查看读入的图像:
img
可见图像在opencv中被储存为array数组。
将图像显示出来:
其中imshow函数将指定图片显示出来。
WaitKey(int k)函数的功能是刷新图像,其中参数k单位是毫秒,表示刷新频率,显示函数和刷新函数一起使用,否则无法正常显示。因为一条指令的执行速率约为0.0000000001s,人眼很难捕捉到,必须通过延时函数才能正确显示。 返回值为k毫秒内键盘按键的ASCII码值。若没有按键,则返回-1。
destroyWindow(winname)函数用来关闭winname所指定的窗口,输入winname是要关闭窗口的窗口名。
#图像的显示,也可以创建多个窗口
cv2.imshow('image',img)
#等待时间,毫秒级,0表示按任意键终止
#waitKey(delay )在一个给定的时间内(单位ms)等待用户按键触发;如果用户没有按下键,则继续等待。有按键按下,返回按键的ASCII值。无按键按下,返回-1
cv2.waitKey(0)
cv2.destroyAllWindows()
显示出图像:
定义一个显示图像用的函数,之后操作更加简便:
#定义一个函数用来显示图像
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
查看图像文件的形状:
img.shape
其中321,400表示图像的像素值尺寸,3表示图像的通道数。rgb彩色图像有三个通道分别为r、g、b(在opencv中储存顺序为bgr),灰度图像有只有一个通道,二值图像仅有黑白两个颜色组成。
将图像转换为灰度图像:
在imread函数读取时可以添加参数转换图像的格式,这里使用cv2.IMREAD_GRAYSCALE将图像抓换为灰度图。
#读取图像将图像转换为灰度图像,第一个参数指定文件,第二个对图像进行转换
img=cv2.imread('C:/photo/happy.jpg',cv2.IMREAD_GRAYSCALE)
print(img,img.shape)
输出数组和shape:
观察可以发现由rgb彩色图像转换为灰度图像后,通道数由原本的3个变为1个。
保存图像:
#保存
cv2.imwrite('veryhappy.jpg',img)
返回true保存成功。
其他:
#查看格式
print(type(img))
#查看像素点个数
print(img.size)
#查看数据类型
print(img.dtype)
相应输出:
2.视频的读取
使用VideoCapture函数读取视频,其可以用来捕获摄像头或捕获视频,括号内为取0,1等数字来选择不同的摄像设备,或直接指定文件路径读取视频文件。
#cv2.VideoCapture可以用来捕获摄像头或捕获视频,括号内为取0,1等数字来选择不同的设备,或直接指定文件路径
vc=cv2.VideoCapture('C:/Users/86158/Videos/movie/沈阳大街.mp4')
读取后检查文件是否能打开:
read()函数用来按帧读取视频,read()有两个返回值,open为布尔值——若读取帧是成功则返回True,如果文件读取到结尾则返回False,Frame返回每一帧的图像。
#检查视频是否能打开,若能打开isopened()返回true
if vc.isOpened():
#若能打开,open被赋予true值,frame被赋予第一帧的图像
open, frame =vc.read()
else:
#无法打开,赋予false
open = False
遍历视频文件,依次读取视频的每一帧并对其处理后显示出来:
while open:
#通过遍历读取每一帧
ret, frame =vc.read()
#如果这一帧为空,即视频结束,停止遍历
if frame is None:
break
#将每一帧的图像转化为灰度图在显示
if ret ==True:
gray =cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('result',gray)
#waitKey(delay )在一个给定的时间内(单位ms)等待用户按键触发;如果用户没有按下键,则继续等待。有按键按下,返回按键的ASCII值。无按键按下,返回-1。
#关于&0xFF可以参考https://blog.csdn.net/qq_31622345/article/details/98070787
#当按esc(ASCII值为27)时,退出while循环
if cv2.waitKey(10) & 0xFF == 27:
break
#release()用来停止捕获视频。
vc.release()
cv2.destroyAllWindows()
输出的结果,将视频中每一帧都转换为灰度图。
3.截取部分图像数据
通过数组切片可以实现图像的裁剪截取操作:
img=cv2.imread('C:/photo/happy.jpg')
#通过数组切片实现对图像的部分截取
cat=img[0:300,0:300,]
cv_show('cat',cat)
截取的部分图像:
4.颜色通道的提取
split()函数用来提取出图像的颜色通道,rgb彩色图像有三个通道分别为r、g、b(在opencv中储存顺序为bgr),灰度图像有只有一个通道。
#通过split()分别提取出三个通道,opencv中三个通道的顺序是bgr
b,g,r=cv2.split(img)
查看其中一个通道中的内容和shape:
r
r.shape
将单独的通道组合为一个rgb图像:
使用merge()函数将通道组合起来。
#merge函数可以将三个通道组合起来
img=cv2.merge((b,g,r))
img.shape
尝试更该通道中的取值查看图像的变化:
将图像中的r,g通道中的数值全部设置为0,只保留b通道。
#只保留b通道
#copy复制图像
cur_img=img.copy()
#把r,g通道的值全部设置为0
cur_img[:,:,1]=0
cur_img[:,:,2]=0
cv_show('B',cur_img)
观察结果发现图像变成了蓝色。
5.边界填充
cv2.copyMakeBorder()方法用于在像相框一样的图像周围创建边框。
用法:
cv2.copyMakeBorder(src, top, bottom, left, right, borderType, value)
参数:
src:它是源图像。
top:它是顶部方向上的像素数的边框宽度。
bottom:它是底部方向上的像素数的边框宽度。
left:它是左侧像素的边界宽度。
right:它是右侧像素数的边框宽度。
borderType:它描述了要添加哪种边框。它由cv2.BORDER_CONSTANT,cv2.BORDER_REFLECT等参数定义
value:这是一个可选参数,如果borderType为cv2.BORDER_CONSTANT
时需要填充的常数值。
填充方法:
BORDER_CONSTANT:它添加一个恒定的彩色边框。该值应作为下一个参数给出。
BORDER_REFLECT:边框将是边框元素的镜像反射。假设,若图像包含字母“abcdefg”,则输出为“gfedcba | abcdefg | gfedcba”。
BORDER_REFLECT_101:它与cv2的工作原理相同。边界反射,但略有变化。假设,若图像包含字母“abcdefgh”,则输出为“gfedcb | abcdefgh | gfedcba”。
BORDER_REPLICATE:它复制最后一个元素。假设,若图像包含字母“abcdefgh”,则输出将为“aaaaa | abcdefgh | hhhh”。
BORDER_WARP:外包装法,输出为“cdefg|abcdefg|abcdefg”
设置五种不同的边界填充方法并输出:
img=cv2.imread('C:/photo/happy.jpg')
#指定上下左右的填充大小值
top_size,bottom_size,left_size,right_size=(50,50,50,50)
replicate=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REPLICATE)
reflect=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REFLECT)
reflect101=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REFLECT101)
wrap=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_WRAP)
constant=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_CONSTANT,value=0)
plt.subplot(231),plt.imshow(img,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
填充结果:
因为 opencv 的接口使用BGR模式,而 matplotlib.pyplot 接口使用的是RGB模式,图像的输出会有色差。
6.数值计算
因为在opencv中图像以ndarray格式储存,故可以在数组上直接进行部分数值运算。
#截取图像数组中的一部分进行数值计算实验
img=cv2.imread('C:/photo/happy.jpg')
img[:5,:5,0]
原始数组为:
在数组上进行数值运算并输出结果:
#直接在ndarry数组上相减
img2=img-10
img2[:5,:5,0]
#对应位置相加,超过255的取余
(img+img2)[:5,:5,0]
#越界的取255
cv2.add(img,img2)[:5,:5,0]
直接相加和cv2.add方法的不同:前者越界的数值进行取余操作,后者越界直接取255。
7.图像融合
addWeighted()方法用于将两个图像加权融合
用法:
cv2.addWeighted(src1, alpha, src2, beta, gamma,dst,dtype)
参数:
第1个参数是图像1 src;
第2个参数是图像1的权值 alpha;
第3个参数为图像2 dst;
第4个参数为图像2的权值 beta;
第5个参数附加数值gamma,单个数值,即使是多通道图像也使用单个数值;
第6个参数可选,返回图像的实例,等同于函数返回结果
第7个参数可选,dtype,表示像素值的数据类型
dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma)。
实例:
首先读取两幅图像并将其转换为相同的尺寸(若不转换无法进行融合)。
img=cv2.imread('C:/photo/happy.jpg')
img_cat=cv2.imread('C:/photo/cat.jpg')
img.shape
#resize函数改变图形尺寸
img_cat=cv2.resize(img_cat,(400,321))
img_cat.shape
使用addWeighted()方法将两个图像加权融合:
res=cv2.addWeighted(img,0.5,img_cat,0.5,0)
cv_show('res',res)
融合效果:
8.图像阈值
threshold()函数用于图像阈值处理
用法:
ret,dst=cv2.threshold(img, threshold, maxval,type)
参数:
ret是返回阈值
dst是返回的输出图像
threshold是设定的阈值
maxval是当灰度值大于(或小于)阈值时将该灰度值赋成的值
type规定的是当前处理的方式
处理方式:
cv2.THRESH_BINARY 大于阈值的部分被置为maxval,小于部分被置为0
cv2.THRESH_BINARY_INV 大于阈值部分被置为0,小于部分被置为maxval
cv2.THRESH_TRUNC 大于阈值部分被置为threshold,小于部分保持原样
cv2.THRESH_TOZERO 小于阈值部分被置为0,大于部分保持不变
cv2.THRESH_TOZERO_INV 大于阈值部分被置为0,小于部分保持不变
五种不同的阈值处理方法通过实例进行对比:
img_gray=cv2.imread('C:/photo/happy.jpg',cv2.IMREAD_GRAYSCALE)
ret,thresh1=cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY)
ret,thresh2=cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3=cv2.threshold(img_gray,127,255,cv2.THRESH_TRUNC)
ret,thresh4=cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO)
ret,thresh5=cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO_INV)
titles=['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images=[img,thresh1,thresh2,thresh3,thresh4,thresh5]
for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
输出结果:
版权声明:本文为博主sen233333原创文章,版权归属原作者,如果侵权,请联系我们删除!
原文链接:https://blog.csdn.net/sen233333/article/details/122648086