本系列文章是继银行卡号实战项目后的图像高级操作教程的第一篇,在银行卡号之前所学的图像操作可以满足大部分场景,但是有一些特殊场景就需要一些高级操作进行处理了
在讲图像特征检测的时候,我们先来聊聊什么是特征,以及特征为什么那么重要,以至于在计算机视觉,机器学习,深度学习中都反复的提到。
百度的解释是:特征为一事物异于其他事物的特点。那我们再来简单的说明一下
特征是 于己而言,特征是某些突出性质的表现,于他而言,特征是区分事物的关键
很难说,人类是如何找到这些特征的,这个能力在我们大脑中早已根深蒂固。对于计算机如何找到这些特征我们还要深入研究,这里我们主要研究图片的特征。
上图非常简单,在图像的顶部,给出了六个小图像补丁。如果现在有一个问题是如何在原始图像中找到这些补丁的确切位置,能找到多少个正确的结果?
A和B是平坦的表明,他们分布在很多区域中。找到这些补丁的确切位置是很难的
C和D要简单很多,他们是建筑物的边缘。我们可以找到一个大概的位置,但确切的位置仍然很困难。
最后 E和F是建筑物的一些角落,它们很容易找到,因为在角落,无论你移动这个补丁,它都会有所不同。所以它们可以是很好的特征。而且我们看 E 和 F 也符合特征的描述很容易区分,也很用它来区分其他事物。
我们在来看一下这个模型
蓝色方块是平坦的区域,很难找到和追踪。只要我们在这个绿色矩形中移动蓝色方块,它看起来好像都一样。
而黑色方块有边缘。如果沿垂直方向(即沿着渐变方向)移动它会改变。沿边缘移动(平行于边缘),看起来都一样。
对于红色方块,它是角落,无论我们怎么移动这个红色方块,它看起来都不同,那意味着他说独一无二的,所以基本上,角点被认为是图像中的好特征(不仅仅是交流,在某些情况下,blob(斑点)也被认为是很好的特征)
但是接下来又会出现一个问题,我们如何找到它们,其实刚才我们已经回答了这一点,即在图像中寻找在起周围的所有区域中移动时具有最大变化的区域。在接下来的章节中,这些将被投射到计算机语言中。因此我们也可以称查找这些图像为特征检测。
我们在图像中找到了这些特征,一旦找到它,我们应该就能够在其他图像中找到相同的内容。这是如何做到的?我们在这个特征周围区域,用中文将就是,“上面是蓝天,下面是建筑物,建筑物上有玻璃”当我们可以这么描述的时候,我们也可以在另一个地方寻找相同的图片。类似的,如果计算机也可以描述特征周围的区域,以便可以在其他图像找到它。那我们称这种描述为特征描述,获得这些特征及其描述后,我们可以在所有图像中找到相同的功能并对齐它们,将它们拼接在一起或做任何我们想做的事情。
讲到这,大家感觉这个特征匹配是不是有一点很像模板匹配,只是这里模板换成了特征,更加的灵活
角点检测:https://blog.csdn.net/SESESssss/article/details/106774854
我们可以从角点具有的特征触发:
即选取一个局部窗口,将这个窗口沿着各个方向移动,计算移动前后窗口内像素的差异的多少进而判断窗口对应的区域是否是较低
有了思想后,我们进一步把它转化为数学描述:
通过公式,我们可以解释为
但事实上,如果我们此时用以上公式进行角点检测,会发现其中的参数 u 和 v 也就是窗口的方向并没有明确的规定。
所以我们也可以人为规定 u 和 v,但是这样一来,指定方向的话,窗口滑动又可能导致检测出来的角点其实是边缘点
既然这样,我们可以指定若干组的 u 和 v,即通过的窗口滑动方向,然后对所以的 u 和 v求得 E后再进行加权平均
然而,Harris角点检测并没有这么做
Harris可能在像,我应该如何优化原始的这个检测函数呢,如何提高精度,降低算法的复杂度
这时候就要用到数学工具:
对E(u,v)表达式进一步演化:
对于不同区域的图像灰度梯度:
平坦区域:两个特征值都小,且近似相等,能量函数在各个方向上都较小;
边缘区域:一个特征值大,另一个特征值小,能量函数在某一方向上增大,其他方向较小;
角点区域:两个特征值都大,且近似相等,能量函数在所有方向上都增大。
这样一来,我们就可以仅通过矩阵M的特征值,来评估图像是否存在角点
但Harris角点的计算方法甚至不需要用到特征值,只需要计算一个Harris响应值R:
到此,通过求出R,我们便可以进行角点检测。(你会发现最后根本不需要代入u,v进行计算)
是不是很神奇,感觉学这样不仅仅是去学习这个技术,更多的是别人处理问题,转化问题的思路
在OpenCV中,我们用 cv2.cornerHarris()进行Harris角点检测。参数如下:
import cv2
import numpy as np
# 导入图片
img = cv2.imread('test_1.jpg')
print ('img.shape:',img.shape)
# 转灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
# 进行Harris角点检测,dst是结果矩阵,保存了最后的结果
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
print ('dst.shape:',dst.shape)
# 这里是设定一个阈值 当大于这个阈值分数的都可以判定为角点
# 这里是如果R>最大的R的0.01倍就认为他是一个角点
img[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img)
cv2.waitKey(0)
cv2.destroyAllWindows(
https://blog.csdn.net/weixin_48167570/article/details/123704075
** 在上一章中,我们学习了角点检测器,如Harris角点检测算法。它们具有旋转不变性,这意味着,即使图像旋转,我们也可以找到相同的角点,因为很明显,角点在旋转图像中也是角点。但是对应缩放呢?如果图像缩放,角点就可以不再是角点。以下图为例,在小图像中使用一个小窗口能够检测出角点,然而将图像放大后,在同一窗口中的图像变得平坦,无法检测出角点。所以 Harris 角点不具有尺度不变性。**
因此,就有了SIFT(Scale Invariant Feature Transform) 尺度不变特征转换算法。
SIFT 算法不仅只有尺度不变性,当旋转图像,改变图像亮度,移动拍摄位置时,仍可以有较好的检测效果
其实,在我们的生活中,SIFT算法已经有所应用,比如,我们手机上的全景拍摄:当我们拿着手机旋转拍摄时,就可以得到一副全景图,其实原理就是我们在旋转拍摄时,拍摄了很多的图像,这些图像相邻之间有重叠部分,把这些图像合在一起,去除重叠部分,就可以得到一幅全景图。
看完步骤后,相信大家还是有点懵,我们接下去带着这些步骤看原理就会理解很多。
我们前几章已经讲述过图像金字塔的概念,在这里我们把图像金字塔与尺度空间相结合
图像金字塔是一种以多分辨率来解释图像的结构,通过对原始图像进行多尺度像素采样的方式,生成N个不同分辨率的图像。把具有最高级别的图像放在底部,以金字塔形状排列,往上是一系列像素逐渐降低的图像,一直到金字塔的顶部只包含一个像素点的图像。
前几章中我们也学习了高斯图像金字塔,这次我们更加深入的了解一下原理
我们先来说一下人的眼睛,我们人眼对世界的感知有两种特性:一是近大远小:同一物体,近处看时感觉比较大,远处看时感觉比较小;二是模糊:更准确说应该是 ‘粗细’。我们看近处,可以看到物体的细节(人会感觉看的比较清晰)。比如一片树叶,近看可以看到树叶的纹理,远处看只能看到树叶的大概轮廓(人会觉得比较模糊)。从频率的角度出发,图像的细节(比如纹理,轮廓等)代表了图像的高频成分,图像较平滑区域标识了图像的低频成分
高斯图像金字塔实际上是一种图像的尺度空间(分线性和非线性空间,此处仅讨论线性空间),尺度的概念用来模拟观察者距物体的远近程度,在模拟物体远近的同时还要考虑物体的粗细程度。
简而言之:图像的尺度就是模拟人眼看到物体的远近程度以及模糊程度。
图像金字塔就考虑了这两个方面:图像的远近程度,图像的模糊程度
如何模拟远近程度
就像我们讲过的,去除掉偶数行和偶数列。
如何模拟模糊程度
采用高斯核对图像进行平滑处理,这也是我们讲过的,高斯卷积核是实现尺度变换的唯一线性核
其实高斯金字塔并不是一个金字塔,而是有很多组(Octave)金字塔构成,并且每组金字塔都包含若干层(Interval)
高斯金字塔构建过程:
这样反复执行,就可以得到一共O组,每组L层,共计O*L个图像,这些图像一起就构成了高斯金字塔,结构如下:
在同一组内,不同层图像的尺寸是一样的,后一层图像的高斯平滑因子是前一层图像平滑因子的k倍;
在不同组内,后一组第一个图像是前一组倒数第三个图像的二分之一采样,图像大小是前一组的一半
高斯金字塔图像效果如下,分别是第 1 组的4层和第2组的 4 层:
创建好高斯图像金字塔后,每一组内的相邻层相减可以得到高斯差分金字塔(DoG,Difference of Gaussian),是后期检测图像极值点的前途,如下图所示:
DOG金字塔的第1组第1层,是由高斯金字塔的第1组第2层减去第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。
概况为 DOG金字塔的第o组第I层图像是由高斯金字塔的第o组第l+1层减去 第o层第I层得到的
每一组在层数上,DOG金字塔比高斯金字塔少一层,后续SIFT特征点的提取都是在DOG金字塔上进行的
DOG金字塔的显示效果如下:
下边对这些DOG图像进行归一化,可以很明显的看到差分图像所蕴含的特征,并且由一些特征是在不同尺度下都存在,这些特征正是SIFT所要提取的稳定特征
其中,T=0.04,可人为设定其值;n为待提取的图像数,abs(val) 为图像的像素值,设点像素阈值,是为了去除一些噪音点或其他一些不稳定像素点。
在高斯差分金字塔中寻找极值点
特征点是由DOG空间的局部极值点组成的,为了寻找DOG函数的极值点,每一个像素点要和它所有的相邻点比较,看其是否比它的图像域和尺度域的相邻点大或者小
如下图所示:在高斯差分金字塔中寻找极值点,处理x,y方向的点,还要考虑方向的点,所以要判断一个像素点是否为极值点,要与周围26个点进行比较
注意:
依次类推。。。。。。。。。
当我们检测到极值点之后,会发现一个问题,高斯差分金字塔是离散的(因为尺度空间和像素点是离散的),所以找到的极值点是不太准确,真正的极值点很有可能在其附近,如下图所示,为了找到更高精度的极值点,需要用到泰勒展开式
上述过程,只是找到关键点并确定了其方向,但SIFT算法核心用途在于图像的匹配,我们需要对关键点进行数学层面的特征描述,也就是构建关键点描述符.
1、确定计算描述子所需的图像区域
描述子梯度方向直方图由关键点所在尺度的高斯图像计算产生. 图像区域的半径通过下式计算
d=4,代表划分4x4个子块
2、将坐标移到关键点方向
关键点所在的半径区域,移至关键点方向,如下图所示
3、生成关键点描述符
将区域划分为4x4的子块,对每一个子块进行8个方向的直方图统计操作,获得每个方向的梯度幅值,总共可以组成128维描述向量。
对于每一个关键点,都拥有位置、尺度以及方向三个信息。为每个关键点建立一个描述符,用一组向量将这个关键点描述出来,使其不随各种变化而改变,比如光照变化、视角变化等等。这个描述子不但包括关键点,也包含关键点周围对其有贡献的像素点,并且描述符应该有较高的独特性,以便于提高特征点正确匹配的概率。
1、分别对模板图(参考图,reference image)和实时图(观测图,observation image)建立关键点描述子集合。目标的识别是通过两点集内关键点描述子的比对来完成。具有128维的关键点描述子的相似性度量采用欧式距离。
2、匹配可采取穷举法完成,但所花费的时间太多。所以一般采用kd树的数据结构来完成搜索。搜索的内容是以目标图像的关键点为基准,搜索与目标图像的特征点最邻近的原图像特征点和次邻近的原图像特征点。
Kd树如下如所示,是个平衡二叉树
Opencv中使用SIFT算法
import cv2
import numpy as np
img = cv2.imread('test_1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 这里因为4以上的版本SIFT因为专利的原因收费了,所以我们要用SIFT的话,版本是3.4.1到3.4.3
cv2.__version__
# 创建一共SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
# 关键点检测,这个None是掩膜,如果想只检测一部分图像时可以使用
kp = sift.detect(gray, None)
# 2.3在图像上绘制关键点的检测结果,img参数是要把特征点画在img上
img = cv2.drawKeypoints(gray, kp, img)
# 根据关键点计算周围区域的特征向量描述
keypoints, descriptor = sift.compute(gray, keypoints)
cv2.imshow('drawKeypoints', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
本篇文章主要讲述的是图像特征的检测,从这里开始之后,就会大量地涉及到高等数学,线性代数,概率论等数学知识,如果那个小伙伴这些基础的数学功底还没打好的话,建议先去巩固一下数学基础
我是Mayphry,从一点点到亿点点,我们下次再见