【python】图像识别(一)
车牌识别项目
简单了解图片灰度化方法
我们为啥要进行灰度化,那是彩色图像不利于进行图像识别,而灰度图像不仅仅压缩了图像,其只有一个数据矩阵方便机器进行数据分析。
我们都知道RGB由三色组成,red,green,blue,这三种颜色组成了其他一切颜色。而灰度图像色素为RGB(r,r,r),其中r的取值为0~256,即灰度值共256个级别。
而我们灰度化处理的方法主要是三种:
(1)最大值法,就是让RGB中的值等于三个r值得最大的那个
(2)平均值法,让RGB得值等于三个r和得平均值
(3)加权平均法,根据重要性给三个组成颜色分配不同的权值,并且让三个r等于他们值得加权平均值,这里写一下计算过程:
R
=
G
=
B
=
(
W
r
R
+
W
g
G
+
W
b
B
)
/
3
R=G=B=(W_rR+W_gG+W_bB)/3
R=G=B=(WrR+WgG+WbB)/3
经过简单的搜索我们知道,人眼对三种色彩的敏感度G>R>B,当
W
r
=
0.299
,
W
g
=
0.587
,
W
b
=
0.114
W_r=0.299,W_g=0.587,W_b=0.114
Wr=0.299,Wg=0.587,Wb=0.114时可以得到最合理的灰度图像
灰
度
值
T
T
=
0.299
R
+
0.587
G
+
0.114
B
灰度值TT=0.299R+0.587G+0.114B
灰度值TT=0.299R+0.587G+0.114B
直方图均衡化方法介绍
我们为什么要花直方图?这应该是你脑子中蹦出来的第一个疑问。
直方图时关于数字图像的数据,即数字图像中每一个灰度与其出现频度之间的统计关系,我们可以从图像上得到很多信息:
- 图像的灰度范围
- 每个灰度级的频度和灰度的分布
- 整幅图像的平均明暗和对比度
然后我们把原来灰度图像的数据直方图进行均衡化,均衡化是改变图像的直方图分布,让图像展现的数据分布均衡一点,不那么集中。
这样可以增加像素灰度值的动态范围,增强图像整体对比度的效果。
使用过p图的同学一定会知道,调整图像的对比度能够改变图像的亮度,在这里我们让图像整体更加清晰一些,从而减少图片中部分地方过明或过暗的情况。
计算方法
- r(均衡化图像灰度)计算公式如下,其中
f
(
x
,
y
)
,
灰
度
范
围
f
m
i
n
和
f
m
a
x
f(x,y),灰度范围f_min和f_max
f(x,y),灰度范围fmin和fmax,直方图正规化为
r
∈
[
0
,
1
]
r\in[0,1]
r∈[0,1]
, L 表 示 为 图 像 灰 度 范 围 r = f − f m i n f m a x − f m i n = f L ,L表示为图像灰度范围 r = \frac{f-f_{min}}{f_{max}-f_{min}} = \frac{f}{L} ,L表示为图像灰度范围r=fmax−fminf−fmin=Lf - new图各个位置概率计算公式,其中
n
k
n_k
nk表示灰度为
r
k
r_k
rk像素数目
P r ( r k ) = n k n P_r(r_k)=\frac{n_k}{n} Pr(rk)=nnk - 灰度映射函数:
总概率不变
P s ( s ) d s = P r ( r ) d r P_s(s)ds=P_r(r)dr Ps(s)ds=Pr(r)dr - 直方图均衡化时
P
s
(
s
)
=
1
P_s(s)=1
Ps(s)=1,式子可以化为:
d s = P s ( s ) P r r d r = P r ( r ) d r 1 = P r ( r ) d r ds=\frac{P_s(s)}{P_r{r}dr}=\frac{P_r(r)dr}{1}=P_r(r)dr ds=PrrdrPs(s)=1Pr(r)dr=Pr(r)dr - 最后对ds积分得到s的函数:
s = T ( r ) = ∫ 0 r P r ( w ) d w s=T(r)=\int{0}^{r}P_r(w)dw s=T(r)=∫0rPr(w)dw - s的离散化函数(离散以后方便计算):
s k = T ( r k ) = ∑ j = 0 k P r ( r j ) = ∑ j = 0 k n j n s_k=T(r_k)=\sum_{j=0}^{k}P_r(r_j)=\sum_{j=0}^{k}\frac{n_j}{n} sk=T(rk)=j=0∑kPr(rj)=j=0∑knnj
最后简要描述一下算法的实现思路:
- 从灰度值为0的地方开始进行渐进统计
- 累加灰度级频度数
- 频率乘以灰度总级数得出来该灰度变换后的灰度级。
- 计算出的 255 s K 255s_K 255sK的值即为我们所求得到像素点,此时就可以通过新的像素点绘图得到灰度图像。
记得补充代码
图像滤波去噪法
一幅原始图像在获取和传输的过程中会受到各种噪声的干扰,这些干扰使图像的质量下降。
我们要认识常见的噪声然后对症下药,典型的噪声有:
- 椒盐噪声,想象一下吃烧烤的时候撒调料,调料落在烧烤上的位置是随机的。而这里的噪声也可以这么理解,他们幅值基本相同,但是出现位置随机
- 随机噪声,这里的随机并不是说噪声分布的随机,而是针对的是噪声的幅度,即每一点都有噪声但是噪声的幅度值是随机的。
- 高斯噪声,这个难以理解,那是你需要先百度一下高斯分布,然后你发现高斯分布就是我们常说的正态分布,是不是就明白了很多呢,这个噪声幅度分布形状是呈正态分布的。注:常常由阻性元件内部产生
- 加性噪声和乘性噪声,这里需要理清楚的是噪声和信号之间的关系,前者图像与图像信号无关,其分布图像可以表示为: f ( x , y ) = g ( x , y ) + n ( x , y ) f(x,y)=g(x,y)+n(x,y) f(x,y)=g(x,y)+n(x,y),是不是只有相加的关系呢。后者的图像则受到图像型号的影响,其分布为 f ( x , y ) = g ( x , y ) + n ( x , y ) g ( x , y ) f(x,y)=g(x,y)+n(x,y)g(x,y) f(x,y)=g(x,y)+n(x,y)g(x,y)
- 量化噪声,这个噪声就很神奇,计算公式里面没有出现输入图像信号的影子,而其反映的是量化过程中存在的量化误差反映到接收端而产生的,噪声大小反映出了原图与显示图像的差异
原理
在认识去噪方法之前,我们需要知道几个滤波原理才能明白去噪方法是怎么执行的
-
通过部分区域的像素点集合计算出他们像素的均值,然后把均值赋值给当前的像素点,并作为处理后图像在该点的灰度值。这种方法称为均值滤波又称线性滤波,主要方法如前面所说为领域平均法。
g ( x , y ) = 1 M ∑ ∫ f ( x , y ) g(x,y)=\frac{1}{M}\sum\int f(x,y) g(x,y)=M1∑∫f(x,y)
其中,M为模板中包含当前像素点在内的像素总个数,s为选取的模板的点的集合 -
利用某一个像素的点的附近领域的点的灰度值的中值代替这个像素点的灰度值,很明显这种方法可以去掉某些突出的像素点,它被称为中值滤波。这种方法使图像更加平滑,所以也可以视为一种局部平滑技术。中值滤波在一定的条件下可以克服另一种方法即线性滤波的缺点(细节处理不好),对于滤除脉冲干扰(图像扫描噪点)是最有效的。中值滤波器处理连续图像窗函数时与线性滤波器工作方式相似,但是他不是加权运算。
取3x3函数窗计算(i,j)为中心函数窗像素中值过程:- 按强度值大小排列像素点
- 选择排序像素集的中间值作为点(i,j)的新值
值得注意的是,我们能够想到,这种方法存在的意义就是为了处理某些不合理的极值点,而某些图像中本来就存在这样的点比如线与尖端,那些图像就不适用于这种方法。
经过中值滤波处理的图像,对于过亮和过暗的图像能够更好的区分背景和字符。
- 正太分布总是统计学里值得讨论的课题,而现实中的确存在大量服从正太分布的数据。正太分布又称为高斯分布,通过高斯函数的形状选择权值的线性平滑滤波器,称为高斯平滑滤波器,显然对于那些服从高斯分布的噪声的效果是显而易见的。
高斯滤波的重要性质是其特殊图像性质所决定的。
对于方法的选择:最简单的方法肯定是线性滤波技术,拥有理论基础和易于实现等特征,大家都喜欢使用它。
去噪方法
进行图像滤波去噪,是为了改善图像质量并有利于提取图像的有效信息。
基于噪声频谱分布的规律和统计特征,图像的特点。常见的图像去噪方法有:
- 空域合成法
- 频域合成法
- 最优合成法
高斯平滑滤波
高斯函数的重要性质(个人理解)
- 二维高斯函数具有旋转对称性:
根据高斯函数图像,也就是正态分布图像我们可以看出,图像是均匀对称分布的。
故滤波器在各个方向上的平滑程度是相同的,一般来说一幅图像的边缘方向是不知道的。
换句话来说就是对于处理算法而言,图像的边缘到底在哪是不知道的。
因此,在滤波之前是无法确定一个方向比另一个方向上要有更多的平滑
也许就是我们所说的图像的随机未知性,图像像素并没有什么可以预测到的分布的像素。
旋转对称性也就意味着滤波器在后续图像处理都会等同处理不会偏向任意一方。 - 高斯函数是单值函数(f(x)=y)。
高斯滤波器用某一像素的领域的加权均值来代替该点的像素值,领域像素点的权值是随着离该像素点的距离的增加而减少(放射性)
边缘是一种图像局部特征
边缘是图像性区域和另一个属性区域的交接处,是区域属性发生突变的地方,是图像中不确定性最大的地方,也是图像信息最集中的地方,图像的边缘包含着丰富的信息。
距离计算中心(所求的像素点)很远的地方的点通过平滑计算后仍然对这个计算中心有很大的影响,那么平滑运算会使图像失真(图像信息丢失) - 傅里叶变化频谱(先深入理解一下频谱图和傅里叶变换)
图像定位处理
边缘检测方法
图像边缘:图像局部特性的不连续性
* 灰度级突变
* 颜色突变
* 纹理结构突变
图像的不连续性:
- 跃迁不连续:图像灰度在一个边界的变化是明显的,灰度值突然发生的“断崖式”变化
- 线条不连续:图像的灰度突然变浅了(不连续的部分),然后又恢复到了正常(连续的部分),可以看作为灰度保持了一个较小的行程又回到了原来的值
几个会接触到的术语:
- 边缘点;边缘段;轮廓
- 边缘检测器:从图像抽取边缘集合的算法
- 边缘连接:无序边缘形成的有序边缘表的过程
- 边缘跟踪:用来确定轮廓图像(经过滤波处理)的搜索过程
差分边缘检测算法
处理差分域时,可用图像的一阶差分直接代替图像函数的导数
f
(
x
+
1
,
y
)
−
f
(
x
,
y
)
f(x+1,y) - f(x,y)
f(x+1,y)−f(x,y)
y方向上的一阶差分:
f
(
x
,
y
+
1
)
−
f
(
x
,
y
)
f(x,y+1) - f(x,y)
f(x,y+1)−f(x,y)
总结原理:基于边缘地带的灰度迅速变换,此时一阶导数达到最大的原理,利用导数算子检测边缘。很少用
Roberts边缘检测
利用局部差分算子寻找边缘的算子,计算对角导数:
t = f[i,j] - f[i+1,j+1]
d = f[i+1,j] - f[i,j+1]
G[i,j] = sqrt(t2+d2)
最终的近似值=abs(t)+abs(d)
Sobel算法
Sobel算子很容易在空间上实现,边缘检测器不但产生了较好的边缘检测效果的同时
由于sobel算子引入了局部平均,使得受到的噪声的影响比较小,使用大的领域的时候,抗噪声会更好,只是会增加计算量同时得到的边缘会更粗
方式:利用像素点上下、左右领域点的灰度加权算法,根据在边缘点处达到极值这一现象进行边缘检测
sobel算子对噪声具有平滑作用,提出了较为精确地边缘方向信息
同时由于局部平均的算法,同时它会检测出许多伪边缘,且边缘定位精度不够高
当对精度要求不是很高的时候就常用这种方式来检测边缘
以上,车牌识别的1/3工作已经完毕,主要包括了:
- 图像灰度处理
- 二值化
- 滤波去噪
- 边缘检测
在后面,我们会继续提到图像裁剪、图像内容识别等内容!
python实现代码
简单的读取图片操作
import cv2
img1 = cv2.imread("test.jpg")
cv2.namedWindow("Image")
cv2.imshow("Image",img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
灰度化处理
import cv2
img = cv2.imread("test.jpg",1)
img1 = cv2.imread("test.jpg",0)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow("img",img)
cv2.imshow("gray1",img1)
cv2.imshow("gray2",gray)
cv2.waitKey(0)
二值化处理
import cv2
# 读入原始图像
img = cv2.imread("test.jpg",1)
img1 = gray.copy()
# 灰度化处理:用于图像二值化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化函数
cv2.threshold(gray,140,255,0,gray)
# 通过窗口展示图片,第一个参数为窗口名,第二个为读取的图盘变量
cv2.imshow('img',img)
cv2.imshow('gray',img1)
cv2.imshow('Binarization',gray)
# 暂停显示
cv2.waitKey(0)
伽马变换
import cv2
import copy
# 读入原始图像
img = cv2.imread('test.jpg',1)
# 灰度化处理
img1 = cv2.imread('test.jpg',0)
# 灰度化处理:用于图像的二值化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 伽马变化
gamma = copy.deepcopy(gray)
rows = img.shape[0]
cols = img.shape[1]
for i in range(rows):
for j in range(cols):
gamma[i][j] = 3*pow(gamma[i][j],0.8)
# 展示图片
cv2.imshow('img',img)
cv2.imshow('gray',img1)
cv2.imshow('gamma',gamma)
# 展示窗口
cv2.waitKey(0)
灰度图像的对数变换
import cv2
import copy
import math
# 读入图像
img = cv2.imread("test.jpg",1)
# 灰度化处理
img1 = cv2.imread('test.jpg',0)
# 灰度化处理:这种灰度化处理用于图像二值化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 对数变换
logc = copy.deepcopy(gray)
rows = img.shape[0]
cols = img.shape[1]
for i in range(rows):
for j in range(cols):
logc[i][j] = 3 * math.log(1 + logc[i][j])
cv2.imshow('img',img)
cv2.imshow('gray',img1)
cv2.imshow('logc',logc)
# 展示图片
cv2.waitKey(0)
灰度图像的反色变换
import cv2
import copy
import math
# 读入原始图像
img = cv2.imread('test.jpg',1)
# 灰度化处理
img1 = cv2.imread("test.jpg",0)
# 灰度化处理:次灰度化处理用于图像二值化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 反色变换
cover = copy.deepcopy(gray)
rows = img.shape[0]
cols = img.shape[1]
for i in range(rows):
for j in range(cols):
cover[i][j] = 255 - cover[i][j]
# 展示图像
cv2.imshow('img',img)
cv2.imshow('gray',gray)
cv2.imshow('cover',cover)
# 展示图片
cv2.waitKey(0)
四个不同的滤波器
import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('test.jpg',1)
# 均值滤波
img_mean = cv2.blur(img,(5,5))
# 高斯滤波
img_Guassian = cv2.GaussianBlur(img,(5,5),0)
# 中值滤波
img_median = cv2.medianBlur(img,5)
# 双边滤波
img_bilater = cv2.bilateralFilter(img,9,75,75)
# 展示图片
cv2.imshow('test',img)
cv2.imshow('mean',img_mean)
cv2.imshow('Guassian',img_Guassian)
cv2.imshow('median',img_median)
cv2.imshow('bilater',img_bilater)
# 展示图像
cv2.waitKey(0)
# blog.csdn.net/qq_27261889/article/80822270
边缘检测
import cv2
from skimage import data,filters,img_as_ubyte
img = cv2.imread('test.jpg',1)
# 最后两个参数的含义:
# 用来选择方向
# 1,1 全方位| 1,0 水平方向| 0,1 竖直方向
edges = cv2.Sobel(img,cv2.CV_16S,1,1) # 不需要进行灰度处理就可以唉
# 转化类型
img_edges = cv2.convertScaleAbs(edges)
cv2.imshow('test',img)
cv2.imshow('edge',img_edges)
cv2.waitKey(0)
img = cv2.imread('test.jpg',0)
# img = data.camera() # 系统自带灰度图像
print(type(img))
# 边缘检测必须要是灰度图像
# .sobel 全方位
# .sobel_h 水平方向
# .sobel_v 竖直方向
edges = filters.sobel(img)
# 浮点型转换成伟整型
edges = img_as_ubyte(edges)
cv2.imshow('test',img)
cv2.imshow('edge',edges)
cv2.waitKey(0)