文章目录
数据读取–图片
读取
每一张图像的最小组成部分就是像素点,他是由很多个像素点组成的,每个像素点的范围是0-255,(0是黑色,亮度最暗,255是白色,亮度最亮)
RGB三色彩空间,一般的图片都是三通道的,可以把它看做是用一个三层矩阵表示,对应的不同像素点在三个颜色通道都会有一个对应的值
import cv2 as cv #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt
#想在绘图完成之后,直接生成,不需要调用show()
%matplotlib inline
img = cv.imread('1.jpg')
读取参数是:图片名,会在当前目录下进行搜索
读取之后得到的结果是:一个三通道的numpy的数组形式
看形状:
img.shape
这是对应的结果:
(400, 400, 3)
注意:
1.形式是【h,w,c】的形式
2.Opencv和PIL对于三通道的读取顺序是有区别的。opencv读取的格式是BG,RPIL(python的图像处理库)是使用RGB打开
展示
#图像的显示,也可以创建多个窗口
cv.imshow('image',img)
#等待/消失时间,毫秒级,0表示任意键终止,不自动终止
cv.waitKey(0)
cv.destroyAllWindows()
在这里呢,有两个点要记:
1.cv.waitKey(0)
这里表示是图片的展示/消失时间,如果参数为0,那么表示按任意键自动退出,如果不为0,那么参数就是自己设定的时间,毫秒级别
2.cv.destroyAllWindows()
官方回答:
您可以调用destroyWindow()或destroyAllWindows()来关闭窗口并取消分配任何相关的内存使用。对于一个简单的程序,实际上不必调用这些函数,因为退出时操作系统会自动关闭应用程序的所有资源和窗口
通俗来讲也就是说:
如果之前没有释放掉内存的操作的话destroyallWIndows会释放掉被那个变量占用的内存
我们把整个图片展示的内容聚合成一个函数:
def cv_show(name,img):
cv.imshow(name,img)
cv.waitKey(0)
cv.destroyAllWindows()
这样在之后的图片展示的时候,直接使用该函数即可
灰度化
img2 = cv.imread('1.jpg',cv.IMREAD_GRAYSCALE)
cv2 IMREAD_COLOR 彩色图像
cv2 IMREAD_GRAYSCALE 灰度图像
我们可以展示图片来观察一下图片的区别:
img是初始图片,他是三通道的彩色图片,而img2是经过灰度化处理的图片,他只有一个通道,只需要亮度来进行表达就行。
此时查看img2的shape
img2.shape
所得结果:
(400, 400)#只有[h,w],没有了c
保存
cv.imwrite('1_gray.jpg',img2)
看图片类型
cv.imwrite('1_gray.jpg',img2)
这个是结果:
numpy.ndarray
看图片像素点的个数
img.size
这个是结果:
480000
看图片对应矩阵每个值的范围
img.dtype
这个是结果:
dtype('uint8')
数据读取–视频
vc = cv.VideoCapture('1.mp4')
#检查是否打开正确
if vc.isOpened():
open,frame = vc.read()
else:
open = False
while open:
#参数:ret:当前帧是否正确读入,frame:每一帧图像对应的三通道矩阵
ret,frame = vc.read()
if frame is None:
break
if ret == True:
gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
cv.imshow('result',gray)
#可以设置让他等待多长时间,或者自动退出,可以设置关闭的按键,27对应的是退出键
if cv.waitKey(10) % 0xFF == 27:
break
vc.release()
cv.destroyAllWindows()
就相当于每一帧一帧地读取视频,相当于处理图片
ROI(你感兴趣的区域)
截取部分图像数据
img = cv.imread('1.jpg')
tree = img[0:200,0:200]
cv_show('tree',tree)
这样就是得到了我们想要的高和宽,然后三通道都截取下来
图片颜色通道提取
b,g,r = cv.split(img)
看b是什么:
array([[190, 192, 194, ..., 175, 165, 159],
[190, 191, 193, ..., 183, 158, 180],
[192, 192, 193, ..., 172, 159, 194],
...,
[ 87, 62, 146, ..., 20, 18, 20],
[ 68, 50, 173, ..., 22, 20, 23],
[ 72, 54, 179, ..., 21, 22, 25]], dtype=uint8)
上面的图片是单矩阵的表达图:
想要把通道分别处理之后,再合到一起:
img=cv.merge((b,g,r))
只保留R的写法
因为opencv的读取方法是BGR的读取方式,所以想要保留某一层通道,注意修改最后的通道数就行了。
#只保留R
cur_img = img.copy()
cur_img[:,:,0]=0
cur_img[:,:,1]=0
cv_show('R',cur_img)
#只保留G
cur_img = img.copy()
cur_img[:,:,0]=0
cur_img[:,:,2]=0
cv_show('R',cur_img)
#只保留B
cur_img = img.copy()
cur_img[:,:,1]=0
cur_img[:,:,2]=0
cv_show('R',cur_img)
边界填充
我们在进行数据读取的时候,一般是采取读取卷积核的形式,也就是[3 * 3]或者[5 * 5]的形式,也就是说会读取到他周围的数据当做一个参照,所以当读取到边缘的数据是,我们需要对于边界进行一个填充,是的我们可以读取到所有的有效信息,防止丢失。
top_size,bottom_size,left_size,right_size = (50,50,50,50)
#区别,borderType:按照什么样的方式来进行填充
replicateto = cv.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv.BORDER_WRAP)
#value就是那个参数,这里设置参数为0,即黑色,也可以设置别的颜色
constant = cv.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv.BORDER_CONSTANT,value = 0)
1.top_size,bottom_size,left_size,right_size分别表示对于图片的上下左右进行填充
2.borderType
BORDER_REPLICATE:复制法,也就是复制最边缘的像素
BORDER_REFLECT:反射法:对感兴趣的图像中的像素在两边进行复制,例如:fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101:反射法:也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
BORDER_WRAP:外包装法,cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT:常量法,常量值填充(value就是那个参数,这里设置参数为0,即黑色,也可以设置别的颜色)
下面是实操:
import matplotlib.pyplot as plt
plt.subplot(231),plt.imshow(img,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicateto,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
这是代码的展示结果:
数值计算
img_tree = cv.imread('1.jpg')
img_flo = cv.imread('2.jpg')
#会在每一个像素点上进行加减
img_tree2 = img_tree+10
img_tree[:5,:,0]
img_tree[:5,:,0]
这里因为一张图片矩阵展示比较大,所以制度去前面5行,观察出区别即可
img_tree[:5,:,0]
array([[190, 192, 194, ..., 175, 165, 159],
[190, 191, 193, ..., 183, 158, 180],
[192, 192, 193, ..., 172, 159, 194],
[194, 194, 193, ..., 168, 180, 176],
[195, 194, 194, ..., 153, 165, 151]], dtype=uint8)
在原有图片每个像素点上面进行加减
img_tree[:5,:,0]
array([[200, 202, 204, ..., 185, 175, 169],
[200, 201, 203, ..., 193, 168, 190],
[202, 202, 203, ..., 182, 169, 204],
[204, 204, 203, ..., 178, 190, 186],
[205, 204, 204, ..., 163, 175, 161]], dtype=uint8)
而当两张图片直接进行加减的时候:
注意:两张图片必须shape相同才可以进行加减
(img_tree+img_tree2)[:5,:,0]
#相当于他们对应像素点的和%256
array([[134, 138, 142, ..., 104, 84, 72],
[134, 136, 140, ..., 120, 70, 114],
[138, 138, 140, ..., 98, 72, 142],
[142, 142, 140, ..., 90, 114, 106],
[144, 142, 142, ..., 60, 84, 56]], dtype=uint8)
当使用add函数的时候:
cv.add(img_tree,img_tree2)[:5,:,0]
#当对应像素点的和大于255,即越界的时候,就为255
array([[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255]], dtype=uint8)
图片融合
img_tree.shape
(400, 400, 3)
img_flo.shape
(1080, 1920, 3)
这里可以发现他们的shape不相同,那么我们需要使resize方法使得他们shape相同
#相加减必须shape相同,参数resize的参数,w,h
img_flo=cv.resize(img_flo,(400,400))
img_flo.shape
之后可以进行融合,他们符合一个公式
R = ax + by + b
这里的x,y表示图片1和图片2
a表示图片1的权重,b表示图片2的权重
b表示偏移量
res = cv.addWeighted(img_tree,0.4,img_flo,0.6,0)
放缩变换
#放缩变换,把前面的值制定成(0,0),可以不说具体数值,但是可以说长和宽之间的倍数关系,下面的意思是,x*3,y*1也就是长变为3倍,高不变
res = cv.resize(img,(0,0),fx = 3,fy = 1)
plt.imshow(res)
#下面的意思是:把第一个点变成(0,0),然后长度不变,高度变成原来的3倍
res = cv.resize(img,(0,0),fx = 1,fy = 3)
plt.imshow(res)
我们也可以选择等比例放大:
res = cv.resize(img,(0,0),fx = 3,fy = 3)
plt.imshow(res)