图像和视频
1.图像
提到图像我们就不得不提到关于图像的若干专业词汇
名词 | 解释 |
---|---|
数字图像 | 计算机保存的图像都是一个一个的像素点,称为数字图像。 |
像素 | 是分辨率 的基本单位,是构成位图的基本单元,每个像素都有自己的颜色 |
分辨率(解析度) | 图像分辨率就是单位英寸内 的像素点数。单位为PPI(Pixels Per Inch) |
灰度 | 表示图像像素明暗程度 的数值,也就是黑白图像 中点的颜色深度 。范围一般为0-255。白色为 255,黑色为0。 |
色调 | 色调是指图像的相对明暗程度,在彩色图像 上表现为颜色 。 |
通道 | ①单通道 :一个像素点只需一个数值表示,只能表示灰度,0为黑色; (二值图&灰度图) ②三通道 :RGB模式,把图像分为红绿蓝三个通道,可以表示彩色,全0表示黑色; ③四通道 :RGBA模式,在RGB基础上加上alpha通道,表示透明度,alpha=0表示全透明 |
对比度 | 不同颜色之间的差别 。对比度=最大灰度值/最小灰度值 |
RGB模型 | 色彩三原色(CMYK) :品红、黄、 青,光学三原色(RGB) :红、绿、 蓝 |
频率 | 灰度值变化剧烈程度的指标,是灰度在平面空间上的梯度。 |
幅值 | 幅值是在一个周期内,交流电瞬时出现的最大绝对值,也是一个正弦波,波峰到波谷的距离的 一半。 |
直方图 | 在图像处理中,经常用到直方图,如颜色直方图 、灰度直方图 等 |
灰度直方图 | 图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所 占的多少,图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横 坐标是灰度级,纵坐标是该灰度级出现的频率。 |
1.1 RGB模型的本质
RGB颜色模型是三维直角坐标颜色单位系统的一个单位正方体
在正方体的主对角线上,各原色的量相等,产生由暗到亮的白色,即灰度。(0,0,0)为黑,(1,1,1)为白,正方体的其他6个角点分别为红,黄,绿,青,蓝和品红
1.2 为什么很多图像识别将彩色图像灰度化?
我们识别物体,最关键的因素是梯度,梯度意味着边缘,这是最本质的部分,而计算梯度,自然就用到灰度图像了。颜色本身,非常容易受到光照等因素的影响,同类的物体颜色有很多变化。所以颜色本身难以提供关键信息。
1.3 将彩色图像灰度化的方法
1.3.1 RGB值转化为浮点数
1.4 图像的取样和量化
图像数字化过程由图像的取样与量化来完成。
数字化坐标值称为取样
,数字化幅度值称为量化
。
名词 | 解释 |
---|---|
取样 | 就是要用多少点来描述一幅图像,取样结果质量的高低就是用图像的分辨率来衡量的 |
量化 | 是指要使用多大范围的数值来表示图像采样之后的一个点。 |
下图为不同的取样对图像的影响:
在图像处理中我们若想放大图像或者缩小图像该怎么办?
此时我们引入两个新的概念 上采样和下采样
1.4.1 上采样
定义
:放大图像(或称为上采样(upsampling)或图像插值(interpolating))的主要目的 是放大原图像,从而可以显示在更高分辨率的显示设备上。
那么我们如何进行上采样呢?这里就提到了一个原理叫做内插值
内插值
顾名思义即通过在像素点之间插入一定的数值来扩充整体图像的大小
常用的插值方法
1.最邻近插值
引用一位大神对最邻近插值的过程简单描述:
举个简单的图像:33 的256级灰度图。假如图像的象素矩阵如下图所示(这个原始图把它叫做源图,Source):
234 38 22
67 44 12
89 65 63
这个矩阵中,元素坐标(x,y)是这样确定的,x从左到右,从0开始,y从上到下,也是从零开始,这是图象处理中最常用的坐标系。
如果想把这副图放大为 44大小的图像,那么该怎么做呢?那么第一步肯定想到的是先把44的矩阵先画出来再说,好了矩阵画出来了,如下所示,当然,矩阵的每个像素都是未知数,等待着我们去填充(这个将要被填充的图的叫做目标图,Destination):
? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ?
然后要往这个空的矩阵里面填值了,要填的值从哪里来来呢?是从源图中来,好,先填写目标图最左上角的象素,坐标为(0,0),那么该坐标对应源图中的坐标可以由如下公式得出srcX=dstX* (srcWidth/dstWidth) , srcY = dstY * (srcHeight/dstHeight)
好了,套用公式,就可以找到对应的原图的坐标了(0(3/4),0*(3/4))=>(00.75,00.75)=>(0,0),找到了源图的对应坐标,就可以把源图中坐标为(0,0)处的234象素值填进去目标图的(0,0)这个位置了。
接下来,如法炮制,寻找目标图中坐标为(1,0)的象素对应源图中的坐标,套用公式:
(10.75,00.75)=>(0.75,0) 结果发现,得到的坐标里面竟然有小数,这可怎么办?计算机里的图像可是数字图像,象素就是最小单位了,象素的坐标都是整数,从来没有小数坐标。这时候采用的一种策略就是采用四舍五入的方法(也可以采用直接舍掉小数位的方法),把非整数坐标转换成整数,好,那么按照四舍五入的方法就得到坐标(1,0),完整的运算过程就是这样的:(10.75,00.75)=>(0.75,0)=>(1,0) 那么就可以再填一个象素到目标矩阵中了,同样是把源图中坐标为(1,0)处的像素值38填入目标图中的坐标。
依次填完每个象素,一幅放大后的图像就诞生了,像素矩阵如下所示:
234 38 22 22
67 44 12 12
89 65 63 63
89 65 63 63
设i+u, j+v(i, j为正整数, u, v为大于零小于1的小数,下同)为待求象素坐标,则待求象素灰 度的值 f(i+u, j+v) 如下图所示:
具体过程
:此图以单位图像举例,当我们在实际场景应用时,我们就是利用int进行处理,对于小于i.5自动归为i, 大于i.5的自动归为i+1,同理j也是如此。详细过程请看代码便知。
最邻近插值的代码实现方法
import numpy as np
def function(img):
#得到源图像的长宽以及通道数
height,width,channels =img.shape
print(height,width,channels)
#建立一个空图像,等会用来装入新生成的图像,数值表示将来的图像是800x800
emptyImage=np.zeros((800,800,channels),np.uint8)
#sh,sw就是放缩的尺度
sh=800/height
sw=800/width
for i in range(800):
for j in range(800):
#int的处理就是邻近插值的核心,对于小于i.5自动归为i 大于i.5的自动归为i+1,同理j也是如此
#这也就是对应上文的srcX=dstX* (srcWidth/dstWidth) , srcY = dstY * (srcHeight/dstHeight),得到的是源图在目标图像上的位置
x=int(i/sh)
y=int(j/sw)
print(x,y)
emptyImage[i,j]=img[x,y]
return emptyImage
img=cv2.imread("lenna.png")
zoom=function(img)
print(zoom.shape)
cv2.imshow("nearest interp",zoom)
cv2.imshow("image",img)
cv2.waitKey(0)
缺点
:这种放大图像的方法叫做最临近插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真;效果不好的根源就是其简单的最临近插值方法引入了严重的图像失真,比如,当由目标图的坐标反推得到的源图的的坐标是一个浮点数的时候,采用了四舍五入的方法,直接采用了和这个浮点数最接近的象素的值,这种方法是很不科学的,当推得坐标值为 0.75的时候,不应该就简单的取为1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目标象素值其实应该根据这个源图中虚拟的点四周的四个真实的点来按照一定的规律计算出来的,这样才能达到更好的缩放效果。
2.双线性插值
再引用大神的简单描述:
双线型内插值算法就是一种比较好的图像缩放算法,它充分的利用了源图中虚拟点四周的四个真实存在的像素值来共同决定目标图中的一个像素值,因此缩放效果比简单的最邻近插值要好很多。
双线性内插值算法描述如下:
对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v) (其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。
比如,象刚才的例子,现在假如目标图的象素坐标为(1,1),那么反推得到的对应于源图的坐标是(0.75 , 0.75), 这其实只是一个概念上的虚拟象素,实际在源图中并不存在这样一个象素,那么目标图的象素(1,1)的取值不能够由这个虚拟象素来决定,而只能由源图的这四个象素共同决定:(0,0)(0,1)(1,0)(1,1),而由于(0.75,0.75)离(1,1)要更近一些,那么(1,1)所起的决定作用更大一些,这从公式1中的系数uv=0.75×0.75就可以体现出来,而(0.75,0.75)离(0,0)最远,所以(0,0)所起的决定作用就要小一些,公式中系数为(1-u)(1-v)=0.25×0.25也体现出了这一特点。
核心公式
: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)
核心思想
:双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。
从上面可知要想具体解决双线性插值问题首先要了解什么是单线性插值
?
单线性插值:已知数据 (x0, y0) 与 (x1, y1),要计算 [x0, x1] 区间内某一位置 x 在直线上的y值。
我们先看下图:
再看下述公式:
我们不难看出其实
y
就是以x与x0,x1三者之间距离
的为权重
,以y0,y1
作为权值
计算出来的。
这样我们就引出双线性插值的计算方法,就是在两个方向分别进行单线性插值!
首先,在X方向上进行两次线性插值计算,然后在Y方向上进行一次插值计算。
在图像处理的时候,我们先根据
srcX=dstX* (srcWidth/dstWidth)
,
srcY = dstY * (srcHeight/dstHeight)
来计算目标像素在源图像中的位置,这里计算的srcX和srcY一般都是浮点数,比如f(1.2, 3.4)这个像素点是虚拟存在的,先找到与它临近的四个实际存在的像素点
(1,3) (2,3)
(1,4) (2,4)
写成f(i+u,j+v)的形式,则u=0.2,v=0.4, i=1, j=3
在沿着X方向差插值时,f(R1)=u(f(Q21)-f(Q11))+f(Q11)
沿着Y方向同理计算。
或者,直接整理一步计算,
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
1.4.2 下采样
定义
:缩小图像(或称为下采样(subsampled)或降采样(downsampled))的主要目的 有两个:1、使得图像符合显示区域的大小;2、生成对应图像的缩略图。
1.4.3 直方图
直方图反映了图像中的灰度分布规律。它描述每个灰度级具有的像素个数,但不包含 这些像素在图像中的位置信息。
下图展示了不同情况下的灰度直方图:
1.4.3.1 直方图均衡化
直方图均衡化
是将原图像的直方图通过变换函数变为均匀的直方图,然后按均匀直方图修改原 图像,从而获得一幅灰度分布均匀的新图像。
直方图均衡化的作用
是图像增强
为了将原图像的亮度范围进行扩展,需要一个映射函数,将原图像的像素值均衡映射到新直 方图中,这个映射函数有两个条件
:
- 为了不打乱原有的顺序,映射后亮、暗的大小关系不能改变,
- 映射后必须在原有的范围内,比如(0-255)
步骤
:
- 依次扫描原始灰度图像的每一个像素,计算出图像的灰度直方图H
- 计算灰度直方图的累加直方图
- 根据累加直方图和直方图均衡化原理得到输入与输出之间的映射关系。
- 最后根据映射关系得到结果:dst(x,y) = H’(src(x,y))进行图像变换
公式解析
:
对于输入图像的任意一个像素p, p∈[0,255], 总能在输出图像里有对应的像素q, q∈[0,255] 使得下面等式成 立(输入和输出的像素总量相等):
其中,输出图像每个灰度级的个数
代入累加直方图公式:
1.4.4 滤波
线性滤波
可以说是图像处理最基本的方法,它可以允许我们对图像进行处理,产生很多不同的效果
1.4.4 卷积
卷积的原理与滤波类似
。但是卷积却有着细小的差别。 卷积操作也是卷积核与图像对应位置的乘积和。但是卷积操作在做乘积之前,需要先 将卷积核翻转180度,之后再做乘积
。
卷积所解决的问题:卷积负责提取图像中的局部特征
卷积效果图:
1.4.4.1 滤波器的规则要求
对于滤波器,也有一定的规则要求:
- 滤波器的大小应该是奇数,这样它才有一个中心,例如3x3,5x5或者7x7。有中心了,也有 了半径的称呼,例如5x5大小的核的半径就是2。
- 滤波器矩阵所有的元素之和应该要等于1,这是为了保证滤波前后图像的亮度保持不变。但 这不是硬性要求。
- 如果滤波器矩阵所有元素之和大于1,那么滤波后的图像就会比原图像更亮,反之,如果小 于1,那么得到的图像就会变暗。如果和为0,图像不会变黑,但也会非常暗。
- 对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,我们将他们直接截 断到0和255之间即可。对于负数,也可以取绝对值
在具体应用中,往往有多个卷积核,可以认为,每个卷积核代表了一种图像模式。
如果某个图像块与此卷积核卷积出的值大,则认为此图像块十分接近于此卷积核。
例如,如果我们设计了6个卷积核,可以理解:我们认为这个图像上有6种底层纹理模式,也就是我 们用6种基础模式就能描绘出一副图像。
1.4.4.2 常用卷积
没有效果的卷积:
平滑均值滤波:
高斯平滑滤波:
图像锐化:
soble边缘检测:
soble边缘检测案例:
1.4.4.3 卷积填充
输入图像与卷积核进行卷积后的结果中损失了部分值,输入图像的边缘被“修剪”掉了(边缘处只检测了部分像素点,丢失了图片边界处的众多信息)。这是因为边缘上的像素永远不会位于卷积核中心,而卷积核也没法扩展到边缘区域以外。
这个结果我们是不能接受的,有时我们还希望输入和输出的大小应该保持一致。为解决这个问题,可以在进行卷积操作前,对原矩阵进行边界填充(Padding),也就是在矩阵的边界上填充一些值,以增加矩阵的大小,通常都用“[公式]”来进行填充的。
1.4.4.4 常用两种填充
same填充
当padding的值是same时进行填充,填充的方式为,当卷积核超过特征图边界时,超过的部分进行补零
valid填充
当padding为valid时,不进行补零,如果卷积核会出现超过特征图边界的情况,则为了避免这种情况的发生,
1.4.4.5 卷积步长
滑动卷积核时,我们会先从输入的左上角开始,每次往左滑动一列或者往下滑动一行逐一计算输出,我们将每次滑动的行数和列数称为Stride(步长)。
卷积过程中,有时需要通过padding来避免信息损失,有时也要在卷积时通过设置的步长(Stride)来压缩一部分信息,或者使输出的尺寸小于输入的尺寸。
Stride的作用
:是成倍缩小尺寸,而这个参数的值就是缩小的具体倍数,比如步幅为2,输出就是输入的1/2;步幅为3,输出就是输入的1/3。以此类推。
下图为步长为1的卷积过程:
下图为padding后进行以stride为2的三通道卷积过程:
(前面我们举例为单通道,实际上,大多数输入图像都有 RGB 3个通道)
卷积的计算公式
:
输入图片的尺寸
:一般用n x n
表示输入的image大小。
卷积核的大小
:一般用 f x f
表示卷积核的大小。
填充(Padding)
:一般用p
来表示填充大小。
步长(Stride)
:一般用 s
来表示步长大小。
输出图片的尺寸
:一般用 o
来表示。
若已知n,f,p,s
可以求o
即可以求出`输出图片的尺寸,公式为: