AI学习笔记之图像与视频
1、图像相关概念
像素
像素是分辨率的单位。像素是构成位图图像最基本的单元,每个像素都有自己的颜色。
分辨率
a)图像分辨率就是单位英寸内像素点数。单位为PPI(Pixels Per inch);
b)在生活中被混用,或者说错误的用作衡量图像内的像素点数量。
灰度
表示图像像素明暗程度的数值,也就是黑白图像中点的颜色深度。范围一般为0~255。白色为255,黑色为0。
色调
各种图像色彩模式下原色的明暗程度,级别范围从0到255,共256级色调。
通道
把图像分解成一个或多个颜色成分:
1)单通道:一个像素点只需一个数值表示,智能表示灰度,0为黑色(二值图和灰度图);
2)三通道:RGB模式,把图像分位红绿蓝三个通道,可以表示彩色,全0表示黑色;
3)四通道:RGBA模式,在RGB的基础上加上alpha通道,表示透明度,alpha=0表示全透明
对比度
指不同颜色之间的差别。对比度=最大灰度值/最小灰度值。
RGB模型
色彩三原色(CMYK):品红、黄、青
光学三原色(RGB):红、绿、蓝
RGB颜色模型是三维直角坐标颜色系统中的一个单位正方体,在正方体的主对角线上,各原色的量相等,产生由暗到量的白色,及灰度。(0,0,0)为黑,(1,1,1)为白,正方体的其他6个角点分别为红、黄、绿、青、蓝、品红。
频率
灰度值变化剧烈程度的指标,是灰度在平面空间上的梯度。
2、图像的取样与量化
数字图像
计算机保存的图像都是一个一个的像素点,称为数字图像。图像数字化过程由图像的取样与量化来完成。
取样
就是要用多少点来描述一幅图像,取样结果质量的高低就是用图像的分辨率来衡量的。
量化
是指要使用多大范围的数值来表示图像采样之后的一个点。数字化坐标值称为取样,数字化幅度值称为量化。
在取样时,若横向的像素数(列数)为M,纵向的像素数(行数)为N,则图像总像素数为M*N个像素。
3、上采样与下采样
上采样
放大图像(或称为上采样(uosampling)或图像插值(interpalating)的主要目的是放大图像,从而可以显示在更高分辨率的显示设备上。其原理为内插值。
常用的插值方法
1、最邻近插值The nearest iterpolation
设
i
+
u
,
j
+
v
(
i
,
j
i+u,j+v(i,j
i+u,j+v(i,j为正整数
,
u
,
v
,u,v
,u,v为大于零小于1的小数,下同
)
)
)为待求像素坐标,则待求像素灰度值
f
(
i
+
u
,
j
+
v
)
f(i+u,j+v)
f(i+u,j+v)如下图所示:
2、双线性插值
f
(
i
+
u
,
j
+
v
)
=
(
1
−
u
)
∗
(
1
−
v
)
∗
f
(
i
,
j
)
+
(
1
−
u
)
∗
v
∗
f
(
i
,
j
+
1
)
+
u
∗
(
1
−
v
)
∗
f
(
i
+
1
,
j
)
+
u
∗
v
∗
f
(
i
+
1
,
j
+
1
)
f(i+u,j+v)=(1-u)*(1-v)*f(i,j)+(1-u)*v*f(i,j+1)+u*(1-v)*f(i+1,j)+u*v*f(i+1,j+1)
f(i+u,j+v)=(1−u)∗(1−v)∗f(i,j)+(1−u)∗v∗f(i,j+1)+u∗(1−v)∗f(i+1,j)+u∗v∗f(i+1,j+1)
y
−
y
0
x
−
x
0
=
y
1
−
y
0
x
1
−
x
0
y
=
x
1
−
x
x
1
−
x
0
y
0
+
x
−
x
0
x
1
−
x
0
y
1
\frac{y-y_0}{x-x_0}=\frac{y_1-y_0}{x_1-x_0}\\y=\frac{x_1-x}{x_1-x_0}y_0+\frac{x-x_0}{x_1-x_0}y_1
x−x0y−y0=x1−x0y1−y0y=x1−x0x1−xy0+x1−x0x−x0y1
在x方向做插值:
f
(
R
1
)
≈
x
2
−
x
x
2
−
x
1
f
(
Q
11
)
+
x
−
x
1
x
2
−
x
1
f
(
Q
21
)
w
h
e
r
e
R
1
=
(
x
1
,
y
1
)
f
(
R
2
)
≈
x
2
−
x
x
2
−
x
1
f
(
Q
12
)
+
x
−
x
1
x
2
−
x
1
f
(
Q
22
)
w
h
e
r
e
R
2
=
(
x
1
,
y
2
)
f(R_1)\approx\frac{x_2-x}{x_2-x_1}f(Q_{11})+\frac{x-x_1}{x_2-x_1}f(Q_{21})\;\;\;where\;\;R_1=(x_1,y_1)\\f(R_2)\approx\frac{x_2-x}{x_2-x_1}f(Q_{12})+\frac{x-x_1}{x_2-x_1}f(Q_{22})\;\;\;where\;\;R_2=(x_1,y_2)
f(R1)≈x2−x1x2−xf(Q11)+x2−x1x−x1f(Q21)whereR1=(x1,y1)f(R2)≈x2−x1x2−xf(Q12)+x2−x1x−x1f(Q22)whereR2=(x1,y2)
在y方向做插值:
f
(
P
)
≈
y
2
−
x
y
2
−
y
1
f
(
R
1
)
+
y
−
y
1
y
2
−
y
1
f
(
R
2
)
f(P)\approx\frac{y_2-x}{y_2-y_1}f(R_1)+\frac{y-y_1}{y_2-y_1}f(R_2)\;
f(P)≈y2−y1y2−xf(R1)+y2−y1y−y1f(R2)
所以,综合起来有:
f
(
x
,
y
)
≈
f
(
Q
11
)
(
x
2
−
x
1
)
(
y
2
−
y
1
)
(
x
2
−
x
)
(
y
2
−
y
)
+
f
(
Q
21
)
(
x
2
−
x
1
)
(
y
2
−
y
1
)
(
x
−
x
1
)
(
y
2
−
y
)
+
f
(
Q
12
)
(
x
2
−
x
1
)
(
y
2
−
y
1
)
(
x
2
−
x
)
(
y
−
y
1
)
+
f
(
Q
22
)
(
x
2
−
x
1
)
(
y
2
−
y
1
)
(
x
−
x
1
)
(
y
−
y
1
)
f(x,y)\approx\frac{f(Q_{11})}{(x_2-x_1)(y_2-y_1)}(x_2-x)(y_2-y)+\frac{f(Q_{21})}{(x_2-x_1)(y_2-y_1)}(x-x_1)(y_2-y)\\+\frac{f(Q_{12})}{(x_2-x_1)(y_2-y_1)}(x_2-x)(y-y_1)+\frac{f(Q_{22})}{(x_2-x_1)(y_2-y_1)}(x-x_1)(y-y_1)
f(x,y)≈(x2−x1)(y2−y1)f(Q11)(x2−x)(y2−y)+(x2−x1)(y2−y1)f(Q21)(x−x1)(y2−y)+(x2−x1)(y2−y1)f(Q12)(x2−x)(y−y1)+(x2−x1)(y2−y1)f(Q22)(x−x1)(y−y1)
下采样
缩小图像(或称为下采样(subsampled)或降采样(downsampled)的主要目的:1)使得图像复合显示区域的大小;2、生成对应图像的缩略图。其原理为(M/s)*(N/s)。
4、直方图
直方图的种类及含义
在图像处理中,经常用到直方图,如颜色直方图、灰度直方图等。
图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示图像分钟各个灰度级所占多少。
图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数,其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。
直方图的性质
1、直方图反映了图像中的灰度级分布规律。它描述每个灰度级具有的像素个数,但不包含折现像素在图像中的位置信息。
2、任何衣服规定的图像都有唯一的直方图与之对应,但不同的图像可以有相同的直方图。
3、如果一幅图像有两个不相连的区域组成,并且每个区域的直方图一致,则整幅图像的直方图是该连个区域的直方图之和。
直方图的应用
获取直方图方法如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
'''
calcHist—计算图像直方图
函数原型:calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
images:图像矩阵,例如:[image]
channels:通道数,例如:0
mask:掩膜,一般为:None
histSize:直方图大小,一般等于灰度级数
ranges:横轴范围
'''
# 灰度图像直方图
# 获取灰度图像
img = cv2.imread("lenna.png", 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 灰度图像的直方图,方法一
plt.subplot(231)
plt.imshow(gray)
plt.title('get histogram method 1 - lenna.png')
plt.subplot(234)
plt.hist(gray.ravel(), 256)
plt.title('get histogram method 1')
# 灰度图像的直方图, 方法二
hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
plt.subplot(232)
plt.imshow(gray)
plt.title('get histogram method 2 - lenna.png')
plt.subplot(235)
plt.plot(hist)
plt.title("get histogram method 2")
plt.xlabel("Bins") # X轴标签
plt.ylabel("# of Pixels") # Y轴标签
plt.xlim([0, 256]) # 设置x坐标轴范围
# 彩色图像直方图
plt.subplot(233)
plt.imshow(img)
plt.title("lenna.png")
plt.subplot(236)
chans = cv2.split(img)
colors = ("b", "g", "r")
for (chan, color) in zip(chans, colors):
hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.title("Flattened Color Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.show()
运行结果如下:
直方图均衡化的基本概念
直方图均衡化是将源图像的直方图通过变换函数变成均匀的直方图,然后按均匀直方图修改原图像,从而获得衣服灰度分布均匀的新图像。直方图均衡化的作用是图像增强。
为了将源图像的亮度范围进行扩展,需要一个映射函数,将原图像的像素值均衡映射到新直方图中,这个映射函数有两个条件:
1、为了不打乱原有的顺序,映射后亮、暗的大小关系不能改变;
2、映射后必须在原有的范围内,比如(0~255)
直方图均衡化的步骤
1、依次扫描原始图像的每一个像素,计算出图像的灰度直方图H
2、计算灰度直方图的累加直方图
3、根据累加直方图和直方图均衡化原理得到输入输出之间的映射关系
4、最后根据映射关系得到结果:
d
s
t
(
x
,
y
)
=
H
′
(
s
r
c
(
x
,
y
)
)
dst(x,y)=H'(src(x,y))
dst(x,y)=H′(src(x,y))进行图像变换。
1、对于输入图像的任意一个像素
p
,
p
∈
[
0
,
255
]
p,p\in\lbrack0,255\rbrack
p,p∈[0,255],总能在输出图像里有对应的像素
q
,
q
∈
[
0
,
255
]
q,q\in\lbrack0,255\rbrack
q,q∈[0,255]使得下面的等式成立(输入和输出的像素总量相等):
∑
k
=
0
p
h
i
s
t
i
n
p
u
t
(
k
)
=
∑
k
=
0
q
h
i
s
t
i
o
u
t
(
k
)
\sum_{k=0}^phist_{input}(k)=\sum_{k=0}^qhist_{iout}(k)
k=0∑phistinput(k)=k=0∑qhistiout(k)
2、其中,输出图像每个灰度级的个数:
h
i
s
t
i
o
u
t
(
k
)
=
H
∗
W
256
,
k
∈
[
0
,
255
]
hist_{iout}(k)=\frac{H\ast W}{256},k\in\lbrack0,255\rbrack
histiout(k)=256H∗W,k∈[0,255]
3、带入累加直方图公式:
∑
k
=
0
p
h
i
s
t
i
n
p
u
t
(
k
)
=
(
q
+
1
)
H
∗
W
256
→
q
≈
∑
k
=
0
p
h
i
s
t
i
n
p
u
t
(
k
)
H
∗
W
∗
256
−
1
\sum_{k=0}^phist_{input}(k)=(q+1)\frac{H\ast W}{256}\rightarrow q\approx\sum_{k=0}^p\frac{hist_{input}(k)}{H\ast W}\ast256-1
k=0∑phistinput(k)=(q+1)256H∗W→q≈k=0∑pH∗Whistinput(k)∗256−1
直方图均衡化代码如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
'''
equalizeHist—直方图均衡化
函数原型: equalizeHist(src, dst=None)
src:图像矩阵(单通道图像)
dst:默认即可
'''
# 获取灰度图像
img = cv2.imread("lenna.png", 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 原图直方图
hist0 = cv2.calcHist([gray], [0], None, [256], [0, 256])
# 灰度图像直方图均衡化
dst = cv2.equalizeHist(gray)
hist1 = cv2.calcHist([dst], [0], None, [256], [0, 256])
plt.figure()
plt.subplot(131), plt.imshow(gray), plt.axis('off'), plt.title('lenna.png')
plt.subplot(132), plt.plot(hist0), plt.title('histogram')
plt.subplot(133), plt.plot(hist1), plt.title('histogram equalization')
plt.show()
运行结果如下:
5、滤波
线性滤波可以说是图像处理最基本的方法,它可以允许我们对图像进行处理,产生很多不同的效果。
6、卷积
卷积的原理
卷积的原理和滤波类似。但是卷积却有着细小的差别。卷积操作也是卷积核与图像对应位置的乘积和,但是卷积操作在做乘积之前,需要先将卷积核翻转180度,之后再做乘积。卷积负责提取图像中的局部特征。
卷积的数学定义:
(
f
∗
g
)
(
t
)
=
∫
R
f
(
x
)
g
(
t
−
x
)
d
x
(f\ast g)(t)=\int_Rf(x)g(t-x)\operatorname dx
(f∗g)(t)=∫Rf(x)g(t−x)dx
一般称为g为作用在f上的filter或kernel。
过滤器、卷积核kernel
对于滤波器,也有一定的规则要求:
1)滤波器的大小应该是奇数,这样他才有一个中心,例如3x3,5x5或7x7。有中心了,也有了半径的称呼,例如5x5大小的核的半径就是2。
2)滤波器矩阵所有元素之和应该要等于1,这是为了保证滤波前后图像的亮度保持不变。但这不是硬性要求。
3)如果滤波器所有元素之和大于1,那么滤波后的图像就会比原来亮,反之,如果小于1,那么得到的图像就会变暗。如果等于0,图像不会变黑,但也会非常暗。
4)对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,我们将他们直接截断到0和255之间。对于负数,也可以取绝对值。
在具体应用中,往往有多个卷积核,可以认为,每个卷积核代表了一种图像模式。如果某个图像块与此卷积核卷积处的值大,则认为此图像十分接近于此卷积核。
用Gx来卷积下面这张图的话,就会在中间黑白边界获得比较大的值。
卷积的应用
一个没有任何效果的卷积
将原像素中间像素值乘1,其余全部乘0,显然像素值不会发生任何变化。
平滑均值滤波
取九个值得平均值代替中间像素值,起到平滑的效果。
高斯平滑
高斯平滑水平和垂直方向呈现高斯分布,更突出了中心点在像素平滑后的权重,相比于均值滤波而言,有着更好的平滑效果。
图像锐化
图像锐化使用的是拉普拉斯变换核函数:
Sobel边缘检测
Sobel更强调了和边缘相邻的像素点对边缘的影响。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("lenna.png", 1)
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
'''
Sobel算子
Sobel算子函数原型如下:
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
前四个是必须的参数:
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
其后是可选的参数:
dst是目标图像;
ksize是Sobel算子的大小,必须为1、3、5、7。
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
'''
img_sobel_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3) # 对x求导
img_sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3) # 对y求导
plt.subplot(131), plt.imshow(img_gray, "gray"), plt.title("Original")
plt.subplot(132), plt.imshow(img_sobel_x, "gray"), plt.title("Sobel_x")
plt.subplot(133), plt.imshow(img_sobel_y, "gray"), plt.title("Sobel_y")
plt.show()
运行结果如下:
卷积解决的问题
卷积负责提取图像中的局部特征
卷积–步长
如果用(f,f)的过滤器来卷积一张(h,w)大小的鱼片,每次移动一个像素的话,那么得出的结果就是(h-f+1,w-f+1)。f是过滤器大小,h和w分别表示图片的高宽。
如果每次不止移动一个像素,而是s个像素(s叫做步长),那么结果会变为:
(
h
−
f
s
+
1
,
w
−
f
s
+
1
)
\left(\frac{h-f}s+1,\frac{w-f}s+1\right)
(sh−f+1,sw−f+1)
存在的问题:
⋅
\cdot
⋅只要是f或s的值比1要大的话,那么每次卷积之后结果的长宽,要比卷积前小一些,造成信息丢失。
卷积–填充(padding)
same(相同)填充
有了填充之后,每次卷积之后的图像大小:
(
h
−
f
s
+
1
,
w
−
f
s
+
1
)
⇒
(
h
−
f
+
2
p
s
+
1
,
w
−
f
+
2
p
s
+
1
)
\left(\frac{h-f}s+1,\frac{w-f}s+1\right)\Rightarrow\left(\frac{h-f+2p}s+1,\frac{w-f+2p}s+1\right)
(sh−f+1,sw−f+1)⇒(sh−f+2p+1,sw−f+2p+1)
此时假设高(宽)不变(same填充)
h
−
f
+
2
p
s
+
1
=
h
⇒
p
=
s
(
h
−
1
)
−
h
+
f
2
\frac{h-f+2p}s+1=h\Rightarrow p=\frac{s(h-1)-h+f}2
sh−f+2p+1=h⇒p=2s(h−1)−h+f
假设步长为1,则有:
p
=
f
−
1
2
p=\frac{f-1}2
p=2f−1
valid(有效)填充
有了填充之后,每次卷积之后图像的大小:
(
h
−
f
+
2
p
s
+
1
,
w
−
f
+
2
p
s
+
1
)
\left(\frac{h-f+2p}s+1,\frac{w-f+2p}s+1\right)
(sh−f+2p+1,sw−f+2p+1)
当遇到分数时,只取正数部分。而这种p=0,然后结果取整数部分的处理方式,就叫做"Valid(有效)填充"