python numpy的数组切片和其中None的意思
参考:https://blog.csdn.net/qq_36490364/article/details/83594271
数组切片中用None
# 那么a和a[:None]有何作用上的差别呢?
a[:None]可以取到此数组的所有元素
np.newaxis
参考:https://blog.csdn.net/weixin_42866962/article/details/82811082
插入新维度
对于[: , np.newaxis] 和 [np.newaxis,:]
是在np.newaxis这里增加1维。
python中图片的float类型和uint8类型
在python图像处理过程中,遇到的RGB图像的值是处于0-255之间的,为了更好的处理图像,通常会将图像值转变到0-1之间
这个处理的过程就是图像的float类型转变为uint8类型过程。
float类型取值范围 :-1 到1 或者 0到1
uint8类型取值范围:0到255
查看数据类型
print(image.dtype)
uint8转float32:先将图片转化为float32类型,再除以255,得到0-1之间的数
import numpy as np
image = image.astype(np.float32) / 255
float32转uint8:每个数乘以255,再转化为uint8
import numpy as np
image = (image * 255).astype(np.uint8)
另一种转换方式:
img = np.float32(cv2.resize(img, (448, 448))) / 225
cv2.imwrite()图像全黑问题
网上看别人遇到的问题,可以借鉴。
查看图片数组的数据类型 img.dtype
,发现现在的格式是float32,本应该要是0-255的整数才行,使用cv2.imwrite()保存能正常cv.imshow的图像是近乎全黑的。
转换一下图片数组的数据类型就好了,float[0.0 - 1.0]数据格式的图片img*255.0,再转成uint8[0-255]。
python图像读取方式总结
python图像读取
BGR:
- cv2.imread(img_path):使用opencv读取图像,直接返回numpy.ndarray对象,通道顺序为BGR,注意是BGR,通道值默认范围0-255。
- 为何是BGR?历史遗留问题。
RGB:
- skimage.io.imread(img_path):直接返回numpy.ndarray()对象,通道顺序为GRB,通道值默认范围0-255.
PIL.Image.open():返回PIL image对象,HWC
# 1.读取显示
from PIL import Image
im = Image.open('lena.png')
im.show()
# 2.PIL Image图片转为numpy数组
im_array = np.array(im)
# 也可以用 np.asarray(im) 区别是 np.array() 是深拷贝,np.asarray() 是浅拷贝
# 3.保存PIL图片
I = Image.open('lena.png')
I.save('new_lena.png')
matplotlib.image.imread():numpy.ndarray对象
不管是RGB还是BGR,都是高度×宽度×通道数,H×W×C的表达方式,而在深度学习中,因为要对不同通道应用卷积,所以用的是另一种方式:C×H×W,就是把每个通道都单独表达成一个二维矩阵。
图像转为torch.Tensor对象
在深度学习中,原始图像需要转换为深度学习框架自定义的数据格式,在pytorch中,需要转为torch.Tensor。
torch.Tensor 高维矩阵的表示: (nSample)x C x H x W
numpy.ndarray 高维矩阵的表示: H x W x C
因此在两者转换的时候需要使用 numpy.transpose( )
方法 。
# ------------np.ndarray转为torch.Tensor------------------------------------
# numpy image: H x W x C
# torch image: C x H x W
# np.transpose( xxx, (2, 0, 1)) # 将 H x W x C 转化为 C x H x W
tensor_skimage = torch.from_numpy(np.transpose(img_skimage, (2, 0, 1)))
tensor_cv = torch.from_numpy(np.transpose(img_cv, (2, 0, 1)))
tensor_pil = torch.from_numpy(np.transpose(img_pil_1, (2, 0, 1)))
- 如果反过来,torch.Tensor转numpy.ndarray
# np.transpose( xxx, (2, 0, 1)) # 将 C x H x W 转化为 H x W x C
img_skimage_2 = np.transpose(tensor_skimage.numpy(), (1, 2, 0))
img_cv_2 = np.transpose(tensor_cv.numpy(), (1, 2, 0))
img_pil_2 = np.transpose(tensor_pil.numpy(), (1, 2, 0))
plt.figure()
for i, im in enumerate([img_skimage_2, img_cv_2, img_pil_2]):
ax = plt.subplot(1, 3, i + 1)
ax.imshow(im)
plt.pause(0.01)
np.transpose()
- 对于一维数组不起作用
对于二维数组:
>>> two=np.arange(16).reshape(4,4)
>>> two
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
>>> two.transpose()
array([[ 0, 4, 8, 12],
[ 1, 5, 9, 13],
[ 2, 6, 10, 14],
[ 3, 7, 11, 15]])
>>> two.transpose(1,0)
array([[ 0, 4, 8, 12],
[ 1, 5, 9, 13],
[ 2, 6, 10, 14],
[ 3, 7, 11, 15]])
以上可见,原数组two的数组两个轴为(x,y),对应的下标为(0,1),np.transpose()传入的参数为(1,0),即将原数组的x,y轴互换。综上,对二维数组的transpose操作就是对原数组的转置操作。
对于三维数组:通常用来交换某两个轴,用于深度学习中,如下,即实现将[H, W, C]的表达方式转为[C, H, W]的表达方式。
np.transpose(image, (2, 0, 1)) # channel first
注意与torch.transpose()的区别,torch.transpose()只能交换两个维度
np.ascontiniusarray()
cv2图像处理
cv2.resize(img, (224, 224))
- 输入:
io.imread(img_name)
img = np.float32(cv2.resize(img, (224,224))) /255
inputs = prepare_input(img)
def prepare_input(image):
image = image.copy()
# 归一化
means = np.array([0.485, 0.456, 0.406])
stds = np.array([0.229, 0.224, 0.225])
image -= means
image /= stds
image = np.ascontiguousarray(np.transpose(image, (2, 0, 1))) # channel first
image = image[np.newaxis, ...] # 增加batch维
return torch.tensor(image, requires_grad=True)
扁平化函数 ravel()
与 flatten()
参考:https://www.cnblogs.com/mzct123/p/8659193.html
在Numpy中经常使用到的操作由扁平化操作,Numpy提供了两个函数进行此操作,他们的功能相同,但在内存上有很大的不同.
from numpy import *
a = arange(12).reshape(3,4)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(a.ravel())
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
print(a.flatten())
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
可以看到这两个函数实现的功能一样,但我们在平时使用的时候flatten()更为合适.在使用过程中flatten()分配了新的内存,但ravel()返回的是一个数组的视图.视图是数组的引用(说引用不太恰当,因为原数组和ravel()返回后的数组的地址并不一样),(但修改视图会导致原数组也被修改),在使用过程中应该注意避免在修改视图时影响原本的数组。
numpy数组的拷贝和视图(注意和list的拷贝的区别)
参考:https://blog.csdn.net/Arrogant_95/article/details/82291226;https://blog.csdn.net/u014465934/article/details/79488819
完全不拷贝:简单的任务是不会对数组或其数据进行拷贝的。
赋值即为引用。
>>> a = np.arange(12)
>>> b = a # 不会创建新的对象
>>> b is a # a和b是同一个ndarray对象的两个名字
True
>>> b.shape = 3,4 # 也会改变a的形状
>>> a.shape
(3, 4)
Python传递可变对象的引用,因此函数调用也不会进行拷贝。
- 视图或浅拷贝
- 不同的数组对象可以共享相同的数据。view方法会创建一个共享原数组数据的新的数组对象。
如果数组A是数组B的视图(view),则称B为A的base(除非B也是视图)。视图数组中的数据实际 上保存在base数组中。
- 对数组切片返回的是其视图(引用)。
- 深拷贝:
- copy方法会对numpy数组和其数据进行完全拷贝,不仅不是一个对象,也不再共享数据。类似于list列表中的deepcopy()。
!!!特别注意,对于list列表而言,
copy()
方法和切片
是浅拷贝,如果list中没有引用其他对象,那么浅拷贝和深拷贝才一样(比如一维度list)
# list 列表的浅拷贝或者切片
c = [1,3,[2,3]]
d = c.copy()
c
>> [1, 3, [2, 3]]
d
>> [1, 3, [2, 3]]
d[2][0] = 999
d[1] = 2
d
>> [1, 2, [999, 3]]
c
>> [1, 3, [999, 3]]
# list列表的深拷贝
import copy
c = [1, 2, [3, 4]]
b = copy.deepcopy(c)
d
>> [1, 2, [3, 4]]
d[0] = 0
d[2][1] = 2
d
>> [0, 2, [3, 2]]
c
>> [1, 2, [3, 4]]
索引相关操作
1、批量赋值
比如在将label转为one-hot编码时:
# y是原label的list,每个元素取值为[0,num_classes)
y = np.array(y, dtype='int')
categorical = np.zeros(n, num_classes, dtype='float32')
categorical[np.arange(n), y] = 1
还有一种方式
np.eye(num_classes)[y]
,目前还不理解
2、对于二维数组, a[0, 0]
和 a[0][0]
是一样的。
数组维度
1、一维numpy array的维度为 (n, )
import numpy as np
a = arange(10)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
a.shape
# (10, )
np.genfromtxt
从文本文件加载数据,并按指定处理缺失值。
import numpy as np
data = np.genfromtxt('waveform.txt',delimiter=',',skip_header=18)
数据以,间隔,忽略前18行
np.row_stack()
在numpy库中,对于矩阵的合并操作用两种方法:
行合并:np.row_stack()
列合并:np.column_stack()
>>> import numpy as np
>>> a=np.arange(16).reshape(4,-1)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
>>> b=np.arange(16,32).reshape(4,-1)
>>> b
array([[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
>>> test=np.row_stack((a,b))#行合并
>>> test
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
>>> test=np.column_stack((a,b))#列合并
>>> test
array([[ 0, 1, 2, 3, 16, 17, 18, 19],
[ 4, 5, 6, 7, 20, 21, 22, 23],
[ 8, 9, 10, 11, 24, 25, 26, 27],
[12, 13, 14, 15, 28, 29, 30, 31]])
>>>