【PCV】学习笔记(一)

用旧钥匙打开新领域的门

参考2020年8月北京第24次印刷版本

warning: 该书较老且代码不全不太符合规范

其中标题数字代表页码

主要还是记录自己的学习记录,因为总结出自己的学习笔记比翻书节省时间,而且可以锻炼自己的思维能力。


基本的图像操作与处理

PIL

  • Python Imaging Library

其中PIL最重要的模块是Image

1
2
from PIL import Image
from pylab import *

其中pylabpyplot区别如下:

参考博客 :pylab和pyplot的区别

原图:

1
2
3
4
5
6
pil_im = Image.open('logo.JPG')
print(pil_im)

# 返回值是一个PIL图像对象
>>>
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=2048x2048 at 0x7FE791E67BB0>

转换为灰度图:

1
2
3
4
pil_gray = pil_im.convert('L')
print(pil_gray)

>>> <PIL.Image.Image image mode=L size=2048x2048 at 0x7FCF4F373DF0>

复制和粘贴图像区域:

1
2
3
4
5
# box大小(左,上,右,下)
box = (100, 100, 1200, 1200)
region = pil_im.crop(box)
region = region.transpose(Image.ROTATE_90)
pil_im.paste(region,box)

Matplotlib

绘制图像、点和线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 读取图像到数组中
im = array(Image.open('logo.JPG'))

# 绘制图像
imshow(im)

# 一些点
x = [100, 100, 400, 400]
y = [200, 500, 200, 500]

# 使用红色星状标记绘制点
plot(x, y, 'r*')

# 绘制连接前两个点的线
plot(x[:2], y[:2])

# 添加标题,显示绘制的图像
title('Plotting: "logp.JPG"')
show()

图像的轮廓和直方图

原图:

轮廓图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from PIL import Image
from pylab import *

# 读取图像到数组中
im = array(Image.open('cat.jpeg').convert('L'))

figure()

# 无颜色显示
gray()
# 轮廓图
contour(im,origin= 'image')

# 表示x轴和y轴的单位长度相同
axis('equal')
# 关闭所有坐标轴线、刻度标记和标签
axis('off')

show()

直方图:表征像素值分布情况

1
2
3
4
5
# 直方图
figure()
# 128理解为多少个柱子
hist(im.flatten(), 128, edgecolor='w')
show()

交互式标注

在一幅图像中标注一些点,或者标注一些训练数据。

以下代码为书中代码,但并未实现,如需实现,请使用cv2

1
2
3
4
5
6
7
8
9
10
11
from PIL import Image
from pylab import *

im = array(Image.open('cat.jpeg'))
print("点仨点")
fig = figure()

imshow(im)
x = ginput(3)
print("你点了",x)
show()

Numpy

图像用数组表示

1
2
3
4
5
6
7
8
9
10
11
12
from PIL import Image
import numpy as np

im = np.array(Image.open('cat.jpeg'))
print(im.shape,im.dtype)

im_g = np.array(Image.open('cat.jpeg').convert('L'), 'f')
print(im_g.shape, im_g.dtype)

>>>
(665, 1182, 3) uint8
(665, 1182) float32

灰度变换

考虑任意函数 ff ,也就是一个变换函数。

定义域和值域相同。

1
2
3
4
5
6
7
im = np.array(Image.open('cat.jpeg').convert('L'))

im2 = 255 - im # 反转

im3 = (100 / 255) * im + 100 # 图像像素区间限制到[100,200]

im4 = 255 * (im / 255) ** 2 # 像素值平方
1
2
3
4
5
6
7
8
9
10
11
12
13
# 分为四个小版块,2*2大小
# 第1张,即左上角
ax = fig.add_subplot(221)
ax.imshow(im, plt.cm.gray)
# 第2张,即右上角
ax = fig.add_subplot(222)
ax.imshow(im2, plt.cm.gray)
# 第3张,即左下角
ax = fig.add_subplot(223)
ax.imshow(im3, plt.cm.gray)
# 第4张,即右下角
ax = fig.add_subplot(224)
ax.imshow(im4, plt.cm.gray)

其中有一个问题从今早开始就一直困扰着我,就是我的灰度图是绿色的,如下:

我怀疑我是色盲- -,但是后来取查了一下,发现plt.imshow()默认是三通道的,所以我们需要在imshow()中添加 plt.cm.gray 参数,才显示正确,说真的,现在都用cv2了…

使用fromarray方法和直接gray的效果很不同:

  • 上图为将array转换为Image
  • 下图为使用plt.cm.gray参数

像素范围在[100, 200]内,所以我个人认为可能是上图比较贴合?

【已解决】结论是下图最贴合

经过读书,发现 fromarray方法需要将数据类型转换回来,所以看下图,左图为将其数据类型转换回来后的图,右图为直接转换,并未按照原类型。

1
2
3
4
5
6
7
8
9
im5 = Image.fromarray(np.uint8(im3)) # 左图将其数据类型转换回来
im6 = Image.fromarray(im3) # 右图直接转换
print(im5)
print(im6)

# 可以看到输出的mode是不同的
>>>
<PIL.Image.Image image mode=L size=1182x665 at 0x7FD867392220>
<PIL.Image.Image image mode=F size=1182x665 at 0x7FD867392AF0>

内置函数将array转换为Image:

1
pil_im = Image.fromarray(im)

如果你并不十分确定输入数据的类型,安全起见,应该先转换回来。 注意,NumPy 总是将数组数据类型转换成能够表示数据的“最低”数据类型。对浮点数做乘积或除法操作会使整数类型的数组变成浮点类型。

直方图均衡化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def histeq(im, nbr_bins=256):
""" 对一幅灰度图进行直方图均衡化 """
''' imtools.py '''
''' page:11 '''

# 计算图像的直方图
imhist, bins = np.histogram(im.flatten(), nbr_bins, density=True)
cdf = imhist.cumsum()
cdf = 255 * cdf / cdf[-1] # 归一化

# 使用累计分布函数的线性插值,计算新的像素值
im2 = np.interp(im.flatten(), bins[:-1], cdf)

return im2.reshape(im.shape), cdf
1
2
3
4
5
6
7
8
9
10
11
im = np.array(Image.open('cat.jpeg').convert('L'))
im2, cdf = imtools.histeq(im)

fig = plt.figure()

ax = fig.add_subplot(211)
ax.imshow(im, plt.cm.gray)
ax = fig.add_subplot(212)
ax.imshow(Image.fromarray(im2))

plt.show()

如图所示,上图为原图转换为灰度图,中间图为均衡函数,右图为均衡化后的结果。

----------到结尾啦!! Hoohoo----------