在python中,列表(list)是一个常用的容器,将要处理的元素放入列表中,需要的时候取出,除了通过单个下标访问外,还可以通过切片的方式访问如arr[2:4],表示取的下标2-3的元素,不包括4,我总结了一下python中切片的常用方式和特殊情况,实际上,只要是实现了__getitem__与__setitem__这两个方法都可以进行切片,下面看代码。
arr = [0,1,2,3,4,5,6]
#下标切片,左包右不包
x = arr[1:3] #[1,2]
#可以为负数,从右边开始数
y = arr[1:-1]#[1,2,3,4,5]
#即使没有那么多元素,也没关系
z = arr[:20]#[0,1,2,3,4,5,6]
#左边不写默认为0,右边不写默认为包括最后一个
w = arr[:-2]#[0,1,2,3,4]
i = arr[2:]#[2,3,4,5,6]
#复制一份,改变j不会改变arr
j = arr[:]
j[0]= 100#[100,1,2,3,4,5,6]
print(arr)#[0,1,2,3,4,5,6]
#左边可以切片,右边如果大于切片长度,会使得原列表边长,反之变短
arr[2:3] = [0,0,0]#变长 [0, 1, 0, 0, 0, 3, 4, 5, 6]
arr[1:5] = [0,0]#变短 [0, 0, 0, 5, 6] 注意:这是在注释上一句的情况况下执行的
除了指定切片的起始和终止下标,还可以指定步长,格式为:arr[start:end:stride],代码如下:
arr = [0,1,2,3,4,5,6]
#步长取1,每个元素都取,就是默认值
a = arr[::1]#[0, 1, 2, 3, 4, 5, 6]
#步长取2,每两个元素取一次,从第一个元素开始
b = arr[::2]#[0, 2, 4, 6]
#步长取-1,从右边开始取,这也是python倒置数组的常见写法
c = arr[::-1]#[6, 5, 4, 3, 2, 1, 0]
#步长取-2,从右边开始两个取一次
d = arr[::-2]#[6, 4, 2, 0]
但是在《Effective Python》中,作者推荐我们不要同时指定起止与步长下标,因为这会导致程序难以理解,比如下面的代码:
arr = [0,1,2,3,4,5,6]
a = arr[-2:2:-1]#[5, 4, 3]
b = arr[-1:2:-2]#[1, 3, 5]
这种时候我们宁愿分成两次来写,保证程序的可读性好
a = arr[::-1]
a = a[1:4]
b = arr[1:-1]
b = b[::2]
好了,说完了列表,下面说说多维切片,特别是在深度学习中,我们经常要对高维数据进行切片,例如在做深度学习模型训练的时候,输入的图片经常是[b,c,h,w],表示批次,通道,图片高和宽,一张图片数据由[c,h,w]组成,所以[b,c,h,w]包含了b张图片,好了,在这种情况下,我有几个需求,该如何实现呢?假设b=100,c = 3,h=224,w,=224
1.取得第5张图片
2.取得第2-10张图片
3.获取第5张图片的第2个通道的数据
4.获取所有图片的第2-3个通道的数据
5.获取第5张图片的第2个通道的裁剪数据(从左上角(20,50)到右下角(100,200),注意,一般图片的坐标轴左上角为原点
下面是实现的代码
import numpy as np
data = np.random.randn(100,3,224,224)#模拟图片数据
# 1.取得第5张图片
img5 = data[5]#(3,224,224)
# 2.取得第2-10张图片
img210 = data[2:10]#(8, 3, 224, 224)
# 3.获取第5张图片的第2个通道的数据
img52 = data[5,2]#(224,224)
# 4.获取所有图片的第2-3个通道的数据
img23 = data[:,1:]#100,2,224,224
# 5.获取第5张图片的第2个通道的裁剪数据(从左上角(20,50)到右下角(100,200)
img52c = data[5,2,50:200,20:100]#(150, 80)
相信看到代码大家都明白了多维是如何进行切片,对于某个维度来说,他的切片方式和一维没有区别,如果要对多维进行切片,那么只要用","分割即可,那么多维切片能不能添加步长的,答案是肯定的,还是以上面的数据为例
data = np.random.randn(100,3,224,224)#模拟图片数据
imgss = data[::2]#(50, 3, 224, 224)
imgss2 = data[::2,::-1,::3,::4]#(50, 3, 75, 56)
考虑到上面的例子还不够直观,我读取一张图片为例,只使用切片实现图片的通道变化、图片裁剪和图片缩放
首先读取图片,原图是这样的
import cv2
#读取图片
img = cv2.imread('lena.jpg')#(512,512,3)
cv2.imshow('img',img)
cv2.waitKey()
然后分别获取BGR通道的图像,因为CV2读取图片的顺序就是B,G,R
import cv2
#读取图片
img = cv2.imread('lena.jpg')#(512,512,3)
b,g,r = img[:,:,0],img[:,:,1],img[:,:,2]
cv2.imshow('b',b)
cv2.imshow('g',g)
cv2.imshow('r',r)
cv2.waitKey()
然后试试裁剪吧
import cv2
#读取图片
img = cv2.imread('lena.jpg')#(512,512,3)
#裁剪图片
imgcrop =img[200:400,200:400,:]#左上角(200,200)右下角(400,400)
cv2.imshow('crop',imgcrop)
cv2.waitKey()
最后试试缩放
import cv2
import numpy as np
#读取图片
img = cv2.imread('lena.jpg')#(512,512,3)
cv2.imshow('img',img)
#利用切片缩小图片,直接两个两个取
imgresize1 =img[::2,::2,:]
cv2.imshow('resize1',imgresize1)
#放大图片,取临近值填充
imgresize2 = np.zeros((img.shape[0]*2,img.shape[1]*2,3),dtype=np.uint8)
imgresize2[::2,::2,:] = img
imgresize2[1::2,::2,:] = img
imgresize2[::2,1::2,:] = img
imgresize2[1::2,1::2,:] = img
cv2.imshow('resize2',imgresize2)
cv2.waitKey()
结果如下: