计算机视觉(OpenCV+TensorFlow)

计算机视觉(OpenCV+TensorFlow)


文章目录

  • 计算机视觉(OpenCV+TensorFlow)
  • 前言
  • 六.图像特征检测
    • 1.特征的理解
    • 2.Harris 角点检测
      • 原始思想:
      • Harris角点检测思想
      • Harris角点算法的基本步骤
    • 3.SIFT算法
      • SIFT算法特点
      • SIFT算法的流程
      • SIFT算法原理
        • 图像金字塔
        • 高斯图像金字塔
        • 高斯图像金字塔总图
        • 高斯差分金子塔
        • 极值点(Key points)的精确定位
        • 确定关键点(极值点)方向
        • 关键点描述
        • 关键点匹配
  • 总结


前言

本系列文章是继银行卡号实战项目后的图像高级操作教程的第一篇,在银行卡号之前所学的图像操作可以满足大部分场景,但是有一些特殊场景就需要一些高级操作进行处理了


六.图像特征检测

1.特征的理解

在讲图像特征检测的时候,我们先来聊聊什么是特征,以及特征为什么那么重要,以至于在计算机视觉,机器学习,深度学习中都反复的提到。

百度的解释是:特征为一事物异于其他事物的特点。那我们再来简单的说明一下
特征是 于己而言,特征是某些突出性质的表现,于他而言,特征是区分事物的关键
很难说,人类是如何找到这些特征的,这个能力在我们大脑中早已根深蒂固。对于计算机如何找到这些特征我们还要深入研究,这里我们主要研究图片的特征。
计算机视觉(OpenCV+TensorFlow)_第1张图片
上图非常简单,在图像的顶部,给出了六个小图像补丁。如果现在有一个问题是如何在原始图像中找到这些补丁的确切位置,能找到多少个正确的结果?

A和B是平坦的表明,他们分布在很多区域中。找到这些补丁的确切位置是很难的
C和D要简单很多,他们是建筑物的边缘。我们可以找到一个大概的位置,但确切的位置仍然很困难。
最后 E和F是建筑物的一些角落,它们很容易找到,因为在角落,无论你移动这个补丁,它都会有所不同。所以它们可以是很好的特征。而且我们看 E 和 F 也符合特征的描述很容易区分,也很用它来区分其他事物。
我们在来看一下这个模型
计算机视觉(OpenCV+TensorFlow)_第2张图片
蓝色方块是平坦的区域,很难找到和追踪。只要我们在这个绿色矩形中移动蓝色方块,它看起来好像都一样。
而黑色方块有边缘。如果沿垂直方向(即沿着渐变方向)移动它会改变。沿边缘移动(平行于边缘),看起来都一样。
对于红色方块,它是角落,无论我们怎么移动这个红色方块,它看起来都不同,那意味着他说独一无二的,所以基本上,角点被认为是图像中的好特征(不仅仅是交流,在某些情况下,blob(斑点)也被认为是很好的特征)
但是接下来又会出现一个问题,我们如何找到它们,其实刚才我们已经回答了这一点,即在图像中寻找在起周围的所有区域中移动时具有最大变化的区域。在接下来的章节中,这些将被投射到计算机语言中。因此我们也可以称查找这些图像为特征检测。
我们在图像中找到了这些特征,一旦找到它,我们应该就能够在其他图像中找到相同的内容。这是如何做到的?我们在这个特征周围区域,用中文将就是,“上面是蓝天,下面是建筑物,建筑物上有玻璃”当我们可以这么描述的时候,我们也可以在另一个地方寻找相同的图片。类似的,如果计算机也可以描述特征周围的区域,以便可以在其他图像找到它。那我们称这种描述为特征描述,获得这些特征及其描述后,我们可以在所有图像中找到相同的功能并对齐它们,将它们拼接在一起或做任何我们想做的事情。
讲到这,大家感觉这个特征匹配是不是有一点很像模板匹配,只是这里模板换成了特征,更加的灵活

2.Harris 角点检测

角点检测:https://blog.csdn.net/SESESssss/article/details/106774854

原始思想:

我们可以从角点具有的特征触发:
即选取一个局部窗口,将这个窗口沿着各个方向移动,计算移动前后窗口内像素的差异的多少进而判断窗口对应的区域是否是较低
有了思想后,我们进一步把它转化为数学描述:
计算机视觉(OpenCV+TensorFlow)_第3张图片
通过公式,我们可以解释为计算机视觉(OpenCV+TensorFlow)_第4张图片
但事实上,如果我们此时用以上公式进行角点检测,会发现其中的参数 u 和 v 也就是窗口的方向并没有明确的规定。
所以我们也可以人为规定 u 和 v,但是这样一来,指定方向的话,窗口滑动又可能导致检测出来的角点其实是边缘点
既然这样,我们可以指定若干组的 u 和 v,即通过的窗口滑动方向,然后对所以的 u 和 v求得 E后再进行加权平均
然而,Harris角点检测并没有这么做
Harris可能在像,我应该如何优化原始的这个检测函数呢,如何提高精度,降低算法的复杂度

Harris角点检测思想

这时候就要用到数学工具:
对E(u,v)表达式进一步演化:
计算机视觉(OpenCV+TensorFlow)_第5张图片
计算机视觉(OpenCV+TensorFlow)_第6张图片
计算机视觉(OpenCV+TensorFlow)_第7张图片
计算机视觉(OpenCV+TensorFlow)_第8张图片
计算机视觉(OpenCV+TensorFlow)_第9张图片
对于不同区域的图像灰度梯度:
计算机视觉(OpenCV+TensorFlow)_第10张图片
计算机视觉(OpenCV+TensorFlow)_第11张图片
平坦区域:两个特征值都小,且近似相等,能量函数在各个方向上都较小;
边缘区域:一个特征值大,另一个特征值小,能量函数在某一方向上增大,其他方向较小;
角点区域:两个特征值都大,且近似相等,能量函数在所有方向上都增大。
计算机视觉(OpenCV+TensorFlow)_第12张图片
这样一来,我们就可以仅通过矩阵M的特征值,来评估图像是否存在角点
但Harris角点的计算方法甚至不需要用到特征值,只需要计算一个Harris响应值R
image.png
计算机视觉(OpenCV+TensorFlow)_第13张图片
计算机视觉(OpenCV+TensorFlow)_第14张图片
到此,通过求出R,我们便可以进行角点检测。(你会发现最后根本不需要代入u,v进行计算)
是不是很神奇,感觉学这样不仅仅是去学习这个技术,更多的是别人处理问题,转化问题的思路

Harris角点算法的基本步骤

  1. 计算窗口中各像素点在x和y方向的梯度
  2. 计算两个方向梯度的成绩,即Ix2,Iy2,Ix^iy
  3. 使用滤波核对窗口的每一个像素进行加强,生成矩阵M和元素A,B,C
  4. 计算每个像素的Harris响应值R,并对小于某阈值T的R置0
  5. 由于角点所在区域的一定领域内都有可能被检测为角点,所以为了防止角点矩阵,最后在一个卷积核中进行非极大值抑制,局部最大值点即为角点

在OpenCV中,我们用 cv2.cornerHarris()进行Harris角点检测。参数如下:

  • img:数据类型为 floar32的输入图像
  • blockSize:角点检测中要考虑的邻域大小
  • ksize:Sobel 求导中使用的窗口大小
  • k:Harris 角点检测方程中的自由参数,范围为[0.04,0.06]
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(

3.SIFT算法

https://blog.csdn.net/weixin_48167570/article/details/123704075

** 在上一章中,我们学习了角点检测器,如Harris角点检测算法。它们具有旋转不变性,这意味着,即使图像旋转,我们也可以找到相同的角点,因为很明显,角点在旋转图像中也是角点。但是对应缩放呢?如果图像缩放,角点就可以不再是角点。以下图为例,在小图像中使用一个小窗口能够检测出角点,然而将图像放大后,在同一窗口中的图像变得平坦,无法检测出角点。所以 Harris 角点不具有尺度不变性。**

计算机视觉(OpenCV+TensorFlow)_第15张图片
因此,就有了SIFT(Scale Invariant Feature Transform) 尺度不变特征转换算法。
SIFT 算法不仅只有尺度不变性,当旋转图像,改变图像亮度,移动拍摄位置时,仍可以有较好的检测效果
其实,在我们的生活中,SIFT算法已经有所应用,比如,我们手机上的全景拍摄:当我们拿着手机旋转拍摄时,就可以得到一副全景图,其实原理就是我们在旋转拍摄时,拍摄了很多的图像,这些图像相邻之间有重叠部分,把这些图像合在一起,去除重叠部分,就可以得到一幅全景图。

SIFT算法特点

  • 具有较好的**稳定性和不变性,**能够适当旋转,尺度缩放,便高度的变化,能在一定程度上不受视角变化,仿射变换,噪声的干扰
  • **区分型好,**能够在海量特征数据库中进行快速准确的区分信息进行匹配
  • 多属性:就算只有单个物体,也能产生大量特征向量
  • 高速性:能够快速的进行特征向量匹配。
  • 可拓展性:能够与其他形式的特征向量进行联合

SIFT算法的流程

  1. 提取关键点:关键点是一些十分突出的不会因光照,尺度,旋转等因素而消失的点,比如角点,边缘点,暗区越的暗点。此步骤是搜索所有尺度空间上的图像位置。通过高斯微分函数来识别潜在的具有尺度和旋转不变的兴趣点。
  2. 定位关键点并确定特征方向:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。然后基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据操作都相对于关键点的方向,尺度和位置进行变换,从而提高对于这些变换的不变性
  3. 通过各关键点的特征向量,进行两两比较找出相互匹配的若干对特征点,建立景物间的对应关系。

看完步骤后,相信大家还是有点懵,我们接下去带着这些步骤看原理就会理解很多。

SIFT算法原理

图像金字塔

我们前几章已经讲述过图像金字塔的概念,在这里我们把图像金字塔与尺度空间相结合

图像金字塔是一种以多分辨率来解释图像的结构,通过对原始图像进行多尺度像素采样的方式,生成N个不同分辨率的图像。把具有最高级别的图像放在底部,以金字塔形状排列,往上是一系列像素逐渐降低的图像,一直到金字塔的顶部只包含一个像素点的图像。

高斯图像金字塔

前几章中我们也学习了高斯图像金字塔,这次我们更加深入的了解一下原理

我们先来说一下人的眼睛,我们人眼对世界的感知有两种特性:一是近大远小:同一物体,近处看时感觉比较大,远处看时感觉比较小;二是模糊:更准确说应该是 ‘粗细’。我们看近处,可以看到物体的细节(人会感觉看的比较清晰)。比如一片树叶,近看可以看到树叶的纹理,远处看只能看到树叶的大概轮廓(人会觉得比较模糊)。从频率的角度出发,图像的细节(比如纹理,轮廓等)代表了图像的高频成分,图像较平滑区域标识了图像的低频成分
高斯图像金字塔实际上是一种图像的尺度空间(分线性和非线性空间,此处仅讨论线性空间),尺度的概念用来模拟观察者距物体的远近程度,在模拟物体远近的同时还要考虑物体的粗细程度。
简而言之:图像的尺度就是模拟人眼看到物体的远近程度以及模糊程度。
图像金字塔就考虑了这两个方面:图像的远近程度,图像的模糊程度
如何模拟远近程度
就像我们讲过的,去除掉偶数行和偶数列。
如何模拟模糊程度
采用高斯核对图像进行平滑处理,这也是我们讲过的,高斯卷积核是实现尺度变换的唯一线性核
其实高斯金字塔并不是一个金字塔,而是有很多组(Octave)金字塔构成,并且每组金字塔都包含若干层(Interval)
高斯金字塔构建过程:

  1. 先将原图像扩大一倍之后作为高斯金字塔的第 1 组第 1 层,将第1组第1层图像经过高斯卷积之后作为第1组金字塔的第2层,高斯卷积函数为:计算机视觉(OpenCV+TensorFlow)_第16张图片对于参数image.png在SIFT中取的是固定值 1.6
  2. image.png乘以一个比例系数k,等到一个新的平滑因子image.png=k*image.png,用它来平滑第 1组第2层图像,结果图像作为第3层
  3. 如此这般凡物,最后得到 L 层图像,在同一组中,每一层图像的尺存都是一样的,只是平滑系数不一样,它们对应的平滑系数分别为:image.png
  4. 将第 1 组倒数第三层图像作为比例因子为 2 的降采样,得到的图像作为第2组的第1层,然后对第 2 组的第 1 层图像做平滑因子为 image.png的高斯平滑,得到第2组的第2层,就像步骤2中一样,如此得到第2组的 L 层图像,同组内它们的尺寸是一样的,对应的平滑系数分别为image.png。但是在尺寸方面第 2 组是第1组图像的一半。

这样反复执行,就可以得到一共O组,每组L层,共计O*L个图像,这些图像一起就构成了高斯金字塔,结构如下:
计算机视觉(OpenCV+TensorFlow)_第17张图片
在同一组内,不同层图像的尺寸是一样的,后一层图像的高斯平滑因子image.png是前一层图像平滑因子的k倍;
在不同组内,后一组第一个图像是前一组倒数第三个图像的二分之一采样,图像大小是前一组的一半
高斯金字塔图像效果如下,分别是第 1 组的4层和第2组的 4 层:
计算机视觉(OpenCV+TensorFlow)_第18张图片
计算机视觉(OpenCV+TensorFlow)_第19张图片

高斯图像金字塔总图

计算机视觉(OpenCV+TensorFlow)_第20张图片

高斯差分金子塔

创建好高斯图像金字塔后,每一组内的相邻层相减可以得到高斯差分金字塔(DoG,Difference of Gaussian),是后期检测图像极值点的前途,如下图所示:
DOG金字塔的第1组第1层,是由高斯金字塔的第1组第2层减去第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。
概况为 DOG金字塔的第o组第I层图像是由高斯金字塔的第o组第l+1层减去 第o层第I层得到的
计算机视觉(OpenCV+TensorFlow)_第21张图片
每一组在层数上,DOG金字塔比高斯金字塔少一层,后续SIFT特征点的提取都是在DOG金字塔上进行的
DOG金字塔的显示效果如下:
下边对这些DOG图像进行归一化,可以很明显的看到差分图像所蕴含的特征,并且由一些特征是在不同尺度下都存在,这些特征正是SIFT所要提取的稳定特征
计算机视觉(OpenCV+TensorFlow)_第22张图片

极值点(Key points)的精确定位

计算机视觉(OpenCV+TensorFlow)_第23张图片
其中,T=0.04,可人为设定其值;n为待提取的图像数,abs(val) 为图像的像素值,设点像素阈值,是为了去除一些噪音点或其他一些不稳定像素点。
在高斯差分金字塔中寻找极值点
特征点是由DOG空间的局部极值点组成的,为了寻找DOG函数的极值点,每一个像素点要和它所有的相邻点比较,看其是否比它的图像域和尺度域的相邻点大或者小
如下图所示:在高斯差分金字塔中寻找极值点,处理x,y方向的点,还要考虑image.png方向的点,所以要判断一个像素点是否为极值点,要与周围26个点进行比较
计算机视觉(OpenCV+TensorFlow)_第24张图片
注意:

  1. 如果高斯差分金字塔每组有3层,则只能在中间1层图像寻找极值点,两端的图像不连续,没有极值点
  2. 如果高斯差分金字塔每组有5层,则只能在中间3层图像寻找极值点

依次类推。。。。。。。。。
当我们检测到极值点之后,会发现一个问题,高斯差分金字塔是离散的(因为尺度空间和像素点是离散的),所以找到的极值点是不太准确,真正的极值点很有可能在其附近,如下图所示,为了找到更高精度的极值点,需要用到泰勒展开式
计算机视觉(OpenCV+TensorFlow)_第25张图片
计算机视觉(OpenCV+TensorFlow)_第26张图片
计算机视觉(OpenCV+TensorFlow)_第27张图片

确定关键点(极值点)方向
  1. 通过尺度不变性求极值点,需要利用图像的局部特征为每一个关键点分配一共基准方向,使描述子对图像旋转具有不变性,对于在DOG金字塔中检测出的关键点,采集其所在高斯金字塔图像image.png邻域窗口内像素的梯度和方向分布特征。梯度的模值和方向如下:image.png
  2. 采用梯度直方图统计法,统计以关键点为原点,一定区域内的图像像素点确定关键点方向。在完成关键点的梯度计算后,使用直方图统计邻域内像素的梯度和方向。梯度直方图将0~360度的方向范围分为36个柱,其中每柱10度。如下图所示,直方图的峰值方向代表了关键点的主方向,方向直方图的峰值则代表了该特征点处邻域梯度的方向,以直方图中最大值作为该关键点的主方向。为了增强匹配的鲁棒性,只保留峰值大于主方向峰值80%的方向作为该关键点的辅方向。统计以特征点为圆心,以该特征点所在的高斯图像的尺度的1.5倍为半径的圆内的所有的像素的梯度方向及其梯度幅值,并做1.5σ的高斯滤波(高斯加权,离圆心也就是关键点近的幅值所占权重较高).
关键点描述

上述过程,只是找到关键点并确定了其方向,但SIFT算法核心用途在于图像的匹配,我们需要对关键点进行数学层面的特征描述,也就是构建关键点描述符.
1、确定计算描述子所需的图像区域
描述子梯度方向直方图由关键点所在尺度的高斯图像计算产生. 图像区域的半径通过下式计算计算机视觉(OpenCV+TensorFlow)_第28张图片
d=4,代表划分4x4个子块
2、将坐标移到关键点方向
关键点所在的半径区域,移至关键点方向,如下图所示
计算机视觉(OpenCV+TensorFlow)_第29张图片
3、生成关键点描述符

将区域划分为4x4的子块,对每一个子块进行8个方向的直方图统计操作,获得每个方向的梯度幅值,总共可以组成128维描述向量。
对于每一个关键点,都拥有位置、尺度以及方向三个信息。为每个关键点建立一个描述符,用一组向量将这个关键点描述出来,使其不随各种变化而改变,比如光照变化、视角变化等等。这个描述子不但包括关键点,也包含关键点周围对其有贡献的像素点,并且描述符应该有较高的独特性,以便于提高特征点正确匹配的概率。
计算机视觉(OpenCV+TensorFlow)_第30张图片

关键点匹配

1、分别对模板图(参考图,reference image)和实时图(观测图,observation image)建立关键点描述子集合。目标的识别是通过两点集内关键点描述子的比对来完成。具有128维的关键点描述子的相似性度量采用欧式距离。
2、匹配可采取穷举法完成,但所花费的时间太多。所以一般采用kd树的数据结构来完成搜索。搜索的内容是以目标图像的关键点为基准,搜索与目标图像的特征点最邻近的原图像特征点和次邻近的原图像特征点。
Kd树如下如所示,是个平衡二叉树
计算机视觉(OpenCV+TensorFlow)_第31张图片

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,从一点点到亿点点,我们下次再见

你可能感兴趣的:(计算机视觉,opencv,tensorflow)