1. 图像处理的概念与基本操作
图片、GIF、视频
像素:画面中最小的点
问题:图片在计算机中长啥样?
灰度图片
# 引入依赖包 %matplotlib inline import numpy as import matplotlib.pyplot as plt import paddle from PIL import Image
# 加载一张手写数字的灰度图片 # 从Paddle2.0内置数据集中加载手写数字数据集,本文第3章会进一步说明 from paddle.vision.datasets import MNIST # 选择测试集 mnist = MNIST(mode='test') # 遍历手写数字的测试集 for i in range(len(mnist)): # 取出第一张图片 if i == 0: sample = mnist[i] # 打印第一张图片的形状和标签 print(sample[0].size, sample[1])
Cache file /home/aistudio/.cache/paddle/dataset/mnist/t10k-images-idx3-ubyte.gz not found, downloading https://dataset.bj.bcebos.com/mnist/t10k-images-idx3-ubyte.gz Begin to download Download finished Cache file /home/aistudio/.cache/paddle/dataset/mnist/t10k-labels-idx1-ubyte.gz not found, downloading https://dataset.bj.bcebos.com/mnist/t10k-labels-idx1-ubyte.gz Begin to download .. Download finished (28, 28) [7]
# 查看测试集第一个数字 plt.imshow(mnist[0][0]) print('手写数字是:', mnist[0][1])
手写数字是: [7] /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/cbook/__init__.py:2349: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working if isinstance(obj, collections.Iterator): /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/cbook/__init__.py:2366: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working return list(data) if isinstance(data, collections.MappingView) else data
# 将图片转为矩阵表示 np.array(mnist[0][0])
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 84, 185, 159, 151, 60, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 222, 254, 254, 254, 254, 241, 198, 198, 198, 198, 198, 198, 198, 198, 170, 52, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 67, 114, 72, 114, 163, 227, 254, 225, 254, 254, 254, 250, 229, 254, 254, 140, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 66, 14, 67, 67, 67, 59, 21, 236, 254, 106, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 253, 209, 18, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 233, 255, 83, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 254, 238, 44, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 249, 254, 62, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 254, 187, 5, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 205, 248, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 254, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 251, 240, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 221, 254, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 203, 254, 219, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 254, 254, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 224, 254, 115, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 254, 254, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 242, 254, 254, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 254, 254, 219, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 254, 207, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
# 看不清?不妨把上面的矩阵保存成txt,但是如果直接保存,会变成科学计数法,查看一下np.savetxt()的用法 ?np.savetxt
# 将矩阵保存成文本,数字格式为整数 np.savetxt('7.txt', np.array(mnist[0][0]), fmt='%4d')
- 灰度值与光学三原色(RGB):红、绿、蓝(靛蓝)。光学三原色混合后,组成像素点的显示颜色,三原色同时相加为
- 白色,白色属于无色系(黑白灰)中的一种。
- 参考资料:常用RGB颜色
JEPG格式彩色图片
img = Image.open('lena.jpg')
img
# 将图片转为矩阵表示 np.array(img)
# 使用PIL分离颜色通道 r,g,b = img.split()
??r.crop
# 获取r通道转的灰度图 r
# 获取第一个通道转的灰度图 img.getchannel(0)
# 获取g通道转的灰度图 g
# 获取第二个通道转的灰度图 img.getchannel(1)
# 获取b通道转的灰度图 b
# 获取第二个通道转的灰度图 img.getchannel(2)
# 将矩阵保存成文本,数字格式为整数 np.savetxt('lena-r.txt', r, fmt='%4d') np.savetxt('lena-g.txt', g, fmt='%4d') np.savetxt('lena-b.txt', b, fmt='%4d')
# PIL库的crop函数做简单的图片裁剪 r.crop((100,100,128,128))
# 将裁剪后图片的矩阵保存成文本,数字格式为整数 np.savetxt('lena-r-crop.txt', r.crop((100,100,128,128)), fmt='%4d')
分辨率=画面水平方向的像素值 * 画面垂直方向的像素值
屏幕分辨率
例如,屏幕分辨率是1024×768,也就是说设备屏幕的水平方向上有1024个像素点,垂直方向上有768个像素点。像素的大小是没有固定长度的,不同设备上一个单位像素色块的大小是不一样的。
例如,尺寸面积大小相同的两块屏幕,分辨率大小可以是不一样的,分辨率高的屏幕上面像素点(色块)就多,所以屏幕内可以展示的画面就更细致,单个色块面积更小。而分辨率低的屏幕上像素点(色块)更少,单个像素面积更大,可以显示的画面就没那么细致。
图像分辨率
例如,一张图片分辨率是500x200,也就是说这张图片在屏幕上按1:1放大时,水平方向有500个像素点(色块),垂直方向有200个像素点(色块)。
在同一台设备上,图片分辨率越高,这张图片1:1放大时,图片面积越大;图片分辨率越低,这张图片1:1缩放时,图片面积越小。(可以理解为图片的像素点和屏幕的像素点是一个一个对应的)。
但是,在屏幕上把图片超过100%放大时,为什么图片上像素色块也变的越大,其实是设备通过算法对图像进行了像素补足,我们把图片放的很大后看到的一块一块的方格子,虽然理解为一个图像像素,但是其实是已经补充了很多个屏幕像素;同理,把图片小于100%缩小时,也是通过算法将图片像素进行减少。
# 将图片第一行的像素点逐个取出 np.array(img)[0]
array([[224, 136, 126], [225, 137, 127], [225, 137, 127], ..., [236, 148, 136], [232, 142, 131], [198, 105, 97]], dtype=uint8)
图像的基本概念
- 常见图片格式:jpg、png、gif、psd、tiff、bmp等
- 参考资料:几种常见图片格式的区别
# 加载一张png格式的图片 img = Image.open('cat.png')
# 观察一下图片的形状,通道数,在RGB三通道的基础上,额外增加了一个alpha通道 np.array(img).shape
(2180, 1911, 4)
# 不断调试,找到猫的边缘,裁剪出一小块交接区 img.crop((1450,1450,1500,1500))
# 观察裁剪后图片的第4个通道的信息 np.array(img.crop((1450,1450,1500,1500)))[:,:,3]
array([[ 0, 0, 0, ..., 0, 0, 0], [ 0, 0, 0, ..., 0, 0, 0], [ 0, 0, 0, ..., 0, 0, 0], ..., [255, 255, 255, ..., 0, 0, 0], [255, 255, 255, ..., 0, 0, 0], [255, 255, 255, ..., 0, 0, 0]], dtype=uint8)
# 将裁剪后图片的矩阵保存成文本,数字格式为整数 np.savetxt('cat-alpha-crop.txt', np.array(img.crop((1450,1450,1500,1500)))[:,:,3], fmt='%4d')
使用OpenCV加载并保存图片
- 加载图片,显示图片,保存图片
- OpenCV函数:
cv2.imread()
,cv2.imshow()
,cv2.imwrite()
说明
大部分人可能都知道电脑上的彩色图是以RGB(红-绿-蓝,Red-Green-Blue)颜色模式显示的,但OpenCV中彩色图是以B-G-R通道顺序存储的,灰度图只有一个通道。
OpenCV默认使用BGR格式,而RGB和BGR的颜色转换不同,即使转换为灰度也是如此。一些开发人员认为R+G+B/3对于灰度是正确的,但最佳灰度值称为亮度(luminosity),并且具有公式:0.21R+0.72G+0.07*B
图像坐标的起始点是在左上角,所以行对应的是y,列对应的是x。
加载图片
使用cv2.imread()
来读入一张图片:
- 参数1:图片的文件名
- 如果图片放在当前文件夹下,直接写文件名就行了,如'lena.jpg'
- 否则需要给出绝对路径,如'D:\OpenCVSamples\lena.jpg'
- 参数2:读入方式,省略即采用默认值
cv2.IMREAD_COLOR
:彩色图,默认值(1)cv2.IMREAD_GRAYSCALE
:灰度图(0)cv2.IMREAD_UNCHANGED
:包含透明通道的彩色图(-1)
经验之谈:路径中不能有中文噢,并且没有加载成功的话是不会报错的,
print(img)
的结果为None,后面处理才会报错,算是个小坑。
# 查看AI Studio上OpenCV版本 # opencv-python 4.1.1.26 !pip list
%matplotlib inline import numpy as np import cv2 import matplotlib.pyplot as plt
# 加载彩色图 img = cv2.imread('lena.jpg', 1) # 将彩色图的BGR通道顺序转成RGB img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 显示图片
<matplotlib.image.AxesImage at 0x7fd0d3a8a390>
# 查看图片的形状 img.shape
(350, 350, 3)
图片属性
# 打印图片的形状 print(img.shape) # 形状中包括行数、列数和通道数 height, width, channels = img.shape # img是灰度图的话:height, width = img.shape img.shape
(350, 350, 3) (350, 350, 3)
# 加载灰度图 img = cv2.imread('lena.jpg', 0) # 将彩色图的BGR通道顺序转成RGB img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img) img.shape
(350, 350, 3)
# 加载彩色图 img = cv2.imread('lena.jpg', 1) # 将彩色图的BGR通道直接转为灰度图 img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) plt.imshow(img,'gray') img.shape
(350, 350) /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/numpy/lib/type_check.py:546: DeprecationWarning: np.asscalar(a) is deprecated since NumPy v1.16, use a.item() instead 'a.item() instead', DeprecationWarning, stacklevel=1)
# 加载灰度图 img = cv2.imread('lena.jpg', 0) # 显示这张灰度图 plt.imshow(img,'gray') img.shape
(350, 350)
# 查看一下plt.imshow的用法 # ?plt.imshow
cv2.imwrite('lena-grey.jpg',img)
True
# 加载四通道图片 img = cv2.imread('cat.png',-1) # 将彩色图的BGR通道顺序转成RGB,注意,在这一步直接丢掉了alpha通道 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img) img.shape
(2180, 1911, 3)
img = cv2.imread('cat.png',-1) # 和上图对比一下 plt.imshow(img) img.shape
(2180, 1911, 4)
# 加载彩色图 img = cv2.imread('cat.png',1) # 不转颜色通道 plt.imshow(img) img.shape
(2180, 1911, 3)
img = cv2.imread('cat.png', 1) # 转颜色通道为RGB img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img) img.shape
(2180, 1911, 3)