- 像素 像素是指由图像的小方格组成的,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所呈现出来的样子。 - 分辨率 图像分辨率指图像中存储的信息量,是每英寸图像内有多少个像素点,分辨率的单位为PPI(Pixels Per Inch),通常叫做像素每英寸。图像分辨率一般被用于ps中,用来改变图像的清晰度。 - 图片的尺寸x图片的分辨率=图片的像素 - 这里的尺寸指的就是照相馆中说的几寸照片 - 而AI图像高与宽则是存储图像的矩阵有几行几列 ### 通俗理解 - 图像有形状(尺寸)和颜色 - 颜色是指RGB(红,绿,蓝),red,green,blue三色 - - 每个颜色的取值范围为[0,255] - AI的图像处理通常都是黑白色的 - 也就是说,AI更关注图像的形状,而不是色彩 - - 图像由像素组成 - 一个像素就是一个值为[0,255]的一个数 |
这里指计算机中的图像,从视觉上看,它与现实相近, 比如电脑中看到大山,马路,楼房,车子等,与现实中看到的相近, 但我们知道,这些事物并没有真的进入电脑, 这时要从两个角度理解: 1. 由于电脑中全是数字/字节/二进制01,所图像在电脑的存储方式只能是数字,我们处理图像就是要去处理图像对应的数字 2. 看不见的数字是如何转换成视觉成像的问题,是显示器或者相机处理的,这个不是我们要关注的问题 处理图像就是要处理与图像对应的 数字矩阵 |
## 数据 1 是一个数,也叫标量,或者张量 [1] 是一个列表,确切讲是1维列表,也可以叫做向量 向量就是n个数值形成的列表 [[1],[2]] 2维列表,它的每1维都是一个1维列表,或者说每1维都是一个向量 也可以说是矩阵 ## 数据shape 数据shape,指数据的形状,或者数据的维度 单个数字没有维度 ```python print("shape----------------------") import numpy as np from numpy.core.fromnumeric import shape print(1,shape(3)) # (),没有 print(2,shape([3])) # (1,),表示第一维的个数为1,第二维没有 print(3,shape([[1],[2]])) # (2, 1) 第一维个数为2,第二维个数为1 print(4,shape([[1,1],[2,2]])) # (2, 2) 第一维个数为2,第二维个数为2 ``` 神经网络模型常用的数据shape,通常 不超过四维 |
### reshape - 将原数组中的所有元素串起来,按新的维度进行组合 ```python import numpy as np a = np.array( [ [ [[1],[255]], [[0],[100] ], ] ]) print("1",a) print("2",a.shape) b = a.reshape(2,2) print("3",b) ``` ``` 1 [[[[ 1] [255]] [[ 0] [100]]]] 2 (1, 2, 2, 1) 3 [[ 1 255] [ 0 100]] ``` reshape不改变数组元素具体的值,也不改变元素的个数,改变了数组的形状, 数据进入模型后,会经过很多方法的处理, 不同的方法需要的数组的shape不一样, 所以有时需要改变数据的shape |
新增1个维度-在最高维增加 - 元素个数不变的情况下,再加1维(维度数为1) ```python import numpy as np w = np.array([1,2,3]) print(w.shape) """ (3,) 行向量第2个维度为空 下面增加一个维度,新的维度为(3,1),表示3行1列 """ w = w.reshape(3,1) ``` 新增1个维度-矩阵 由于数据的元素不变化,reshape新的维度后,数据会重排列, 可以利用这一点,为数据增加一个维度, 新的维度要能刚好放下原来所有的数据才行,还需要考虑整除的问题, 如果这加上的一维的维度数不是1,比如是3,就直接报错了 - 下面矩阵最后一个维度是一个行向量 ```python import numpy as np a = np.array( [ [ [1, 2, 55], [0, 3, 10], [1, 2, 55], ] ]) print("1",a) print("2",a.shape) b = a.reshape(1,3,3,1) print("3",b) print("4",b.shape) ``` ``` 1 [[[ 1 2 55] [ 0 3 10] [ 1 2 55]]] 2 (1, 3, 3) 3 [[[[ 1] [ 2] [55]] [[ 0] [ 3] [10]] [[ 1] [ 2] [55]]]] 4 (1, 3, 3, 1) ``` |
### 单个图像shape - 一张图像的矩阵表示 - 下面是一张图片,185是高,宽是358 - 以jpg格式存储,然后使用numpy读取 ```python from PIL import Image import numpy as np im = np.array(Image.open('/tmp/31.jpg')) print(im.dtype) # uint8 print(im.shape) (185, 358, 3) ``` - RGB图像的shape为(高,宽,RGB颜色) - 第3维,表示的是[红,黄,蓝]三色, - 也叫:通道 - - 高宽决定图片的尺寸 - png图片还有一个透明度的维度,它的通道数为4 - 所以通道表示的是高与宽形成的矩阵数量 - - 每个通道的矩阵表示了相似的图片形状,不同的颜色 下面是png图片,每张图片有4组数据 ```python from PIL import Image import numpy as np im = np.array(Image.open('/tmp/1.png')) print(im.shape) # (61, 97, 4) ``` ### 图像通道 - 下面是一张5行2列3通道的白色图片 - 白色对应的RGB是三个255,图像数据最后一维是一个行向量[255,255,255] ```python from PIL import Image import numpy as np im = np.array(Image.open('/tmp/12.jpg')) print(im.shape) # (5, 2, 3) print(im) """ [[[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]]] """ ```
from matplotlib import pyplot as plt from PIL import Image from torchvision import transforms import cv2 图像处理上面四个够用,其他的,比如pandas,也可以进行图像绘制及处理
plt.imread
import os from matplotlib import pyplot as plt from aisty import input img_path1 = os.path.join(input.img_path1, "dianzi1.jpg") # type(img):numpy.ndarray img = plt.imread(fname=img_path1) # plt.imshow(X=img) # img.shape # (1280, 561, 3) # 取其中一色的图像 img1 = img[:, :, 1] # shpae: (1280, 561) H, W = img1.shape img2 = img1[H//3:, :] # 截取三分之二 plt.imshow(X=img2, cmap="gray")
Image.open
import numpy as np from PIL import Image img = Image.open(fp="/opt/tpf/aiwks/datasets/images/001/dianzi1.jpg") print(type(img)) # class 'PIL.JpegImagePlugin.JpegImageFile' print(img.size) # (561, 1280) (宽, 高) img = np.array(img) print(img.shape) # (1280, 561, 3) (高,宽,通道) 强调一下,Image经numpy转换后, 最后一维是3,即类似[1,255,255]这样的格式,是一个维数为3的向量,代表的是RGB三色
图像处理之从PIL读取到模型输入
from PIL import Image from torchvision.transforms import Compose from torchvision.transforms import Grayscale from torchvision.transforms import Resize from torchvision.transforms import ToTensor from torchvision.transforms import Normalize img = Image.open(fp="/opt/tpf/aiwks/datasets/images/001/dianzi1.jpg") # 图像数据预处理 transforms1 = Compose(transforms=[Resize(size=(224, 224)), ToTensor()]) # Compose的参数要求是JpegImageFile x = transforms1(img) print(x.shape) # torch.Size([3, 224, 224]),注意这里shape已经进行了转换 print(x[0,0][:5]) # tensor([0.0863, 0.0863, 0.0863, 0.0863, 0.0863]),还完成了归一化,将0-255的数值转换到0-1 # Normalize标准化处理,图像有3通道,所以需要3个维度进行归一化 transforms2 = Compose(transforms= [Resize(size=(224, 224)), ToTensor(), Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])]) x = transforms2(img) print(x.shape) # torch.Size([3, 224, 224]) # 灰度处理,图像有1通道,所以需要1个维度进行归一化 transforms3 = Compose([ Grayscale(), Resize(size=(32,32)), ToTensor(), Normalize(mean=[0.5], std=[0.5]) ]) x = transforms3(img) print("灰度处理:",x.shape) # 灰度处理: torch.Size([1, 32, 32])
是否灰度处理看业务需求: 如果业务更关注形状,就灰度处理减少计算量 如果不同的颜色对业务分类有帮助,就不进行灰度处理 Normalize(mean=[0.5], std=[0.5]) 将数据拉到0与1的中间,并且转为正态分布
按比例 随机 批量 生成 以x为中心的值
import numpy as np def shake(x): float_num = [0.1, 0.1, 0.3, 0.5, 0.95, 0.95, 0.99, 0.99, 0.99, 0.99] seed = float_num[np.random.randint(0, len(float_num))] x = 100 x = x + np.random.randint(int(-x * seed), int(x * seed)) return x for i in range(5): x = shake(100) print(x) 输出: 107 105 126 85 34
按比例 随机 批量 生成 以图像为中心的其他图像
参考上面的思路,进行以下设计: 要生成的图像通常是正方形,所以求图像的高h,宽w 中的最大值 msize = max(h,w) 以此值为中心,按上面的方法抖动一下,生成一批边 求出图像的中心坐标(cx,cy)按上面的方法抖动一下,得到一系列中心坐标 新的中心+新的边长 对应 新的正方形 存在的问题: 比如x=100,原图像最大边长110,但随机生成的值却有126这样的数据, 所以并不是所有生成的图像都要,要除大于某个值的数据 既然图像变大可能出问题,那么可以将原初的坐标框收缩一下, 这样再随机扩大后,可以减少要去除的框的个数
图像偏移率
(原坐标 - 新坐标)/ 新的最大边长 = 偏移率 所有点的 偏移率之和 就是 损失函数 损失函数的目标是 让程序框到的图像 离 真实标签框的图像 的偏移率 越来越小 如此,程序框 就逐渐逼近 标签框 了