计算机视觉二:局部图像描述子

  • 一、序
    • 1、角点(corner points)
    • 2. 如何判断是否是好的角点检测算法
  • 二、Harris角点检测器
    • 1、基本思想
    • 2、数学表达
    • 3、角点计算流程
    • 4、算法实现
      • 4.1 角点响应函数
      • 4.2 筛选角点
      • 4.3 显示角点
      • 4.4 结果显示
    • 5. 寻找对应点
      • 5.1 兴趣点描述子
        • 5.1.1 获取图像像素块,并使用归一化的互相关矩阵进行比较
        • 结果显示
  • 三、SIFT算法
    • 1、产生
    • 2、了解
      • 2.1 兴趣点
      • 2.2 描述子
      • 2.3 检测兴趣点
      • 2.4 匹配描述子
  • 四、匹配地理标记图像
    • 1、下载地理标记图像
    • 2、使用局部描述子匹配
    • 3、可视化连接的图像

一、序

局部图像描述子主要是为了寻找图像间的对应点和对应区域。以下内容将出现两种用于图像匹配的局部描述子算法。
特征匹配的基本流程:

  1. 根据特定准则,提取图像中的特征点
  2. 提取特征点周围的图像块,构造特征描述符
  3. 通过特征描述符对比,实现特征匹配
    特征点必须具有不变性

特征可以分为以下几类:

  1. 角点:Harris算子,SUSAN算子。FSAT算子
  2. 梯度特征点:SIFT、SURF、GLOH、ASIFT、PSIFT算子
  3. 边缘特征(线性):Canny算子、Marr算子
  4. 纹理特征:灰度共生矩阵,小波Gabor算子
  5. 快速特征匹配的基本策略:以图像中稳定角点的领域训练特征分类器,为输入图像的特征分类

1、角点(corner points)

局部窗口沿各方向移动,均产生明显变化的点
图像局部曲率突变的点

经典的角点检测算法
Harris角点检测
CSS角点检测

2. 如何判断是否是好的角点检测算法

  • 检测出图像中“真实的”角点
  • 准确的定位性能
  • 很高的稳定性
  • 具有对噪声的鲁棒性
  • 具有较高的计算效率

二、Harris角点检测器

1、基本思想

从图像局部的小窗口观察图像特征,利用角点定义判断,如下图

如果在平坦区域:那么超任意方向移动,都无灰度变化
如果在边缘处移动:沿着边缘方向移动,无灰度变化
在角点处:沿任意方向移动,有明显的灰度变化

2、数学表达

将图像窗口平移==[u,v]产生灰度变化E(u,v)==

我们可以利用泰勒展开来获得上图式子中的E和I
窗口函数的两种表示:

对于局部微小的移动量[u,v],我们可以获得以下近似值

M是由图像的导数求得的2X2的矩阵。
所以窗口移动导致的图像变化量其实就是对对称矩阵M的特征值分析,通过两个特征值的大小我们可以对图像点进行分类:

当两个特征值都很小时,图像窗口在所有方向上移动都无明显灰度变化
我们可以定义一个角点响应函数R:


我们将上面的区域划分换一种划分方式,则为:

我们可以看到:
在角点时:R为大叔之正数
在边缘点时:R为大数值负数
在平坦区时:R为小数值

3、角点计算流程

  1. 对角点响应函数R进行阈值处理
    R>threshold
  2. 提取R的局部极大值

为了消除参数k的影响,也可以采用商来计算响应:

4、算法实现

4.1 角点响应函数

from scipy.ndimage import filtersdef compute_harris_response(im,sigma=3):""" Compute the Harris corner detector response function for each pixel in a graylevel image. """imx = zeros(im.shape)filters.gaussian_filter(im, (sigma,sigma), (0,1), imx)imy = zeros(im.shape)filters.gaussian_filter(im, (sigma,sigma), (1,0), imy)Wxx = filters.gaussian_filter(imx*imx,sigma)Wxy = filters.gaussian_filter(imx*imy,sigma)Wyy = filters.gaussian_filter(imy*imy,sigma)Wdet = Wxx*Wyy - Wxy**2Wtr = Wxx + Wyyreturn Wdet / (Wtr*Wtr)

4.2 筛选角点

def get_harris_points(harrisim,min_dist=10,threshold=0.1):# find top corner candidates above a thresholdcorner_threshold = harrisim.max() * thresholdharrisim_t = (harrisim > corner_threshold) * 1# get coordinates of candidatescoords = array(harrisim_t.nonzero()).T# ...and their valuescandidate_values = [harrisim[c[0],c[1]] for c in coords]# sort candidatesindex = argsort(candidate_values)# store allowed point locations in arrayallowed_locations = zeros(harrisim.shape)allowed_locations[min_dist:-min_dist,min_dist:-min_dist] = 1# select the best points taking min_distance into accountfiltered_coords = []for i in index:if allowed_locations[coords[i,0],coords[i,1]] == 1:filtered_coords.append(coords[i])allowed_locations[(coords[i,0]-min_dist):(coords[i,0]+min_dist), (coords[i,1]-min_dist):(coords[i,1]+min_dist)] = 0return filtered_coords

4.3 显示角点

def plot_harris_points(image,filtered_coords):figure()gray()imshow(image)plot([p[1] for p in filtered_coords],[p[0] for p in filtered_coords],'*')axis('off')show()

4.4 结果显示

原图:

5. 寻找对应点

5.1 兴趣点描述子

分配给兴趣点的一个向量,描述该点附近的图像的表观信息。描述子约到,寻找到的对应点越好。描述子通常是由周围图像像素块的灰度值,以及用于比较归一互相关矩阵构成的。

5.1.1 获取图像像素块,并使用归一化的互相关矩阵进行比较

def get_descriptors(image,filtered_coords,wid=5):desc = []for coords in filtered_coords:patch = image[coords[0]-wid:coords[0]+wid+1,coords[1]-wid:coords[1]+wid+1].flatten()desc.append(patch)return descdef match(desc1,desc2,threshold=0.5):n = len(desc1[0])# pair-wise distancesd = -ones((len(desc1),len(desc2)))for i in range(len(desc1)):for j in range(len(desc2)):d1 = (desc1[i] - mean(desc1[i])) / std(desc1[i])d2 = (desc2[j] - mean(desc2[j])) / std(desc2[j])ncc_value = sum(d1 * d2) / (n-1) if ncc_value > threshold:d[i,j] = ncc_valuendx = argsort(-d)matchscores = ndx[:,0]return matchscoresdef match_twosided(desc1,desc2,threshold=0.5):matches_12 = match(desc1,desc2,threshold)matches_21 = match(desc2,desc1,threshold)ndx_12 = where(matches_12 >= 0)[0]# remove matches that are not symmetricfor n in ndx_12:if matches_21[matches_12[n]] != n:matches_12[n] = -1return matches_12

匹配点可视化

def appendimages(im1,im2):# select the image with the fewest rows and fill in enough empty rowsrows1 = im1.shape[0]    rows2 = im2.shape[0]if rows1 < rows2:im1 = concatenate((im1,zeros((rows2-rows1,im1.shape[1]))),axis=0)elif rows1 > rows2:im2 = concatenate((im2,zeros((rows1-rows2,im2.shape[1]))),axis=0)# if none of these cases they are equal, no filling needed.return concatenate((im1,im2), axis=1)
def plot_matches(im1,im2,locs1,locs2,matchscores,show_below=True):im3 = appendimages(im1,im2)if show_below:im3 = vstack((im3,im3))imshow(im3)cols1 = im1.shape[1]for i,m in enumerate(matchscores):if m>0:plot([locs1[i][1],locs2[m][1]+cols1],[locs1[i][0],locs2[m][0]],'c')axis('off')

结果显示


三、SIFT算法

1、产生

David G.Lowe教授总结了基于特征不变技术的检测方法,在图像尺度空间基础上,提出对图像缩放、旋转保存不变性的图像局部特征描述算子–SIFT,即尺度不变特征变换。
SIFT算法可以解决以下问题:

  • 目标的旋转、缩放、平移
  • 图像仿射/投影变换
  • 弱光照影响
  • 部分目标遮挡
  • 杂物场景
  • 噪声

2、了解

实质可以归为在不同尺度空间商查找特征点(关键点)的问题

流程如下:

  1. 提取关键点
  2. 对关键点附加详细信息(局部特征),即描述符
  3. 通过特征点(附带上特征向量的关键点)的两两比较找出相互匹配的若干对特征点,建立对应关系

SIFT要查找的点是一些十分突出的点,不会因光照、尺度、旋转等因素的改变而消失 ,比如:角点、边缘点、暗区域的点以及亮区域的暗点。也就是说SIFT希望选出在尺度、旋转、亮度都具有不变性的点

主要思想是通过对原始图像进行尺度变换,获得图像多尺度下的空间表示。从而实现边缘、角点检测和不同分辨率上的特征提取,以满足特征点的尺度不变性。尺度越大图像越模糊。

2.1 兴趣点

SIFT特征使用高斯差分函数来定位兴趣点:

DoG高斯差分金字塔:对应DOG算子,需构建DOG金字塔
通过高斯差分图像看出图像上的像素值变化情况。如果没有变化,也就没有特征。特征必须是变化尽可能多的点。DOG图像描绘的是目标轮廓。

DOG的局部极值点:特征点是由DOG空间得局部极值点组成的。每一个像素点要和它所有的相邻点比较,看其是否比它的图像域和尺度域的相邻点大或者小。

中间的监测点和它同尺度的8个相邻点和上下相邻尺度对应的9×2个点共26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。

去除边缘响应DOG函数在图像边缘有较强的边缘响应。DOG函数的峰值点在边缘方向有较大的主曲率,在垂直边缘的方向有较小的主曲率。主曲率可以通过计算在该点位置尺度的2×2的Hessian矩阵得到。

2.2 描述子

为了实现旋转不变性,基于每个点周围图像梯度的方向和大小。SIFT描述子又引入参考方向。SIFT描述子使用主方向描述参考方向。

2.3 检测兴趣点

使用开源工具包VLFeat提供的二进制文件来计算图像的SIFT特征。代码如下:

def process_image(imagename,resultname,params="--edge-thresh 10 --peak-thresh 5"):if imagename[-3:] != 'pgm':# create a pgm fileim = Image.open(imagename).convert('L')im.save('tmp.pgm')imagename = 'tmp.pgm'cmmd = str("sift "+imagename+" --output="+resultname+" "+params)os.system(cmmd)print ('processed', imagename, 'to', resultname)#读取特征数值到数值
def read_features_from_file(filename):f = loadtxt(filename)return f[:,:4],f[:,4:]#输出结构保存到特征图片
def write_features_to_file(filename,locs,desc):savetxt(filename,hstack((locs,desc)))#可视化
def plot_features(im,locs,circle=False):def draw_circle(c,r):t = arange(0,1.01,.01)*2*pix = r*cos(t) + c[0]y = r*sin(t) + c[1]plot(x,y,'b',linewidth=2)imshow(im)if circle:for p in locs:draw_circle(p[:2],p[2]) else:plot(locs[:,0],locs[:,1],'ob')axis('off')

2.4 匹配描述子

一图像中的特征匹配到另一幅图像的特征,使用两个特征距离和两个最匹配特征距离的比率。相对于图像的其他特征,该准则保证能够找到足够相似的唯一特征。能够降低错误的匹配数。

代码:

def match(desc1,desc2):desc1 = array([d/linalg.norm(d) for d in desc1])desc2 = array([d/linalg.norm(d) for d in desc2])dist_ratio = 0.6desc1_size = desc1.shapematchscores = zeros((desc1_size[0]),'int')desc2t = desc2.T # precompute matrix transposefor i in range(desc1_size[0]):dotprods = dot(desc1[i,:],desc2t) # vector of dot productsdotprods = 0.9999*dotprods# inverse cosine and sort, return index for features in second imageindx = argsort(arccos(dotprods))# check if nearest neighbor has angle less than dist_ratio times 2ndif arccos(dotprods)[indx[0]] < dist_ratio * arccos(dotprods)[indx[1]]:matchscores[i] = int(indx[0])return matchscores

该函数使用描述子向量间的家教作为距离度量。但是我们需要将描述子向量归一化到单位长度。因为匹配是单向的,所以我们可以先计算第二幅图兴趣点描述子向量的装置矩阵。

为了增加匹配的稳健性,我们可以再反过来执行一次该步骤,从第二幅图象中的特征向第一幅图像中的特征匹配。最后,我们保留同时满足这两种匹配准则的对应。代码如下:

def match_twosided(desc1,desc2):matches_12 = match(desc1,desc2)matches_21 = match(desc2,desc1)ndx_12 = matches_12.nonzero()[0]# remove matches that are not symmetricfor n in ndx_12:if matches_21[int(matches_12[n])] != n:matches_12[n] = 0return matches_12

四、匹配地理标记图像

1、下载地理标记图像

Panoramio下载图像,其提供了一个API接口

import os
import urllib, urlparse
import json# query for images
url = 'http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=0&to=20&minx=-77.037564&miny=38.896662&maxx=-77.035564&maxy=38.898662&size=medium'
c = urllib.urlopen(url)# get the urls of individual images from JSON
j = json.loads(c.read())
imurls = []
for im in j['photos']:imurls.append(im['photo_file_url'])# download images
for url in imurls:image = urllib.URLopener()image.retrieve(url, os.path.basename(urlparse.urlparse(url).path)) print 'downloading:', url

2、使用局部描述子匹配

对图像进行SIFT特征处理后,将特征保存,使用下列代码进行逐个匹配

3、可视化连接的图像

使用pydot工具包进行可视化连接。

创建一个图,图表示深度为2的树,具有5个分支,将分支添加到分支节点上

当匹配的数目高于一个阈值,使用边来连接相应的图像节点。

from pylab import *
from numpy import *
from PIL import Imagefrom PCV.localdescriptors import sift
from PCV.tools import imtoolsimport pydotdownload_path = "panoimages" # set this to the path where you downloaded the panoramio images
path = "/FULLPATH/panoimages/" # path to save thumbnails (pydot needs the full system path)# list of downloaded filenames
imlist = imtools.get_imlist(download_path)
nbr_images = len(imlist)# extract features
featlist = [imname[:-3]+'sift' for imname in imlist]
for i,imname in enumerate(imlist):sift.process_image(imname, featlist[i])matchscores = zeros((nbr_images,nbr_images))for i in range(nbr_images):for j in range(i,nbr_images): # only compute upper triangleprint 'comparing ', imlist[i], imlist[j]l1,d1 = sift.read_features_from_file(featlist[i]) l2,d2 = sift.read_features_from_file(featlist[j])matches = sift.match_twosided(d1,d2)nbr_matches = sum(matches > 0)print 'number of matches = ', nbr_matches matchscores[i,j] = nbr_matches# copy values
for i in range(nbr_images):for j in range(i+1,nbr_images): # no need to copy diagonalmatchscores[j,i] = matchscores[i,j]threshold = 2 # min number of matches needed to create linkg = pydot.Dot(graph_type='graph') # don't want the default directed graph for i in range(nbr_images):for j in range(i+1,nbr_images):if matchscores[i,j] > threshold:# first image in pairim = Image.open(imlist[i])im.thumbnail((100,100))filename = path+str(i)+'.png'im.save(filename) # need temporary files of the right size g.add_node(pydot.Node(str(i),fontcolor='transparent',shape='rectangle',image=filename))# second image in pairim = Image.open(imlist[j])im.thumbnail((100,100))filename = path+str(j)+'.png'im.save(filename) # need temporary files of the right size g.add_node(pydot.Node(str(j),fontcolor='transparent',shape='rectangle',image=filename)) g.add_edge(pydot.Edge(str(i),str(j)))g.write_png('whitehouse.png')

计算机视觉(二):局部图像描述子相关推荐

  1. 【计算机视觉】局部图像描述子:SIFT算法

    文章目录 [计算机视觉]局部图像描述子:SIFT算法 1. SIFT算法的原理 1.1 SIFT算法的目标与思想 1.1.1 算法目标 1.1.2 算法思想 1.2 尺度空间的思想和表示 1.2.1 ...

  2. 【计算机视觉】局部图像描述子

    图像特征匹配与地理标记特征匹配 一.图像特征匹配 1.图像特征点匹配 2.Harris角点检测 2.1角点介绍 2.2Harris算法介绍 2.3Harris角点响应函数R 2.4Harris角点检测 ...

  3. Python计算机视觉编程第二章——局部图像描述子

    Python计算机视觉编程 局部图像描述子 (一)Harris 角点检测器 (二)SIFT(尺度不变特征变换) 2.1 兴趣点 2.2 描述子 2.3 检测兴趣点 2.4 匹配描述子 (三)匹配地理标 ...

  4. 二、【python计算机视觉编程】局部图像描述子

    局部图像描述子 (一)Harris角点检测器 (二)SIFT(尺度不变特征变换) (1)兴趣点 (2)描述子 (3)检测兴趣点 (4)匹配描述子 (三)匹配地理标记图像 (1)从Panoramio下载 ...

  5. 计算机视觉--局部图像描述子

    第二章 局部图像描述子 (一)SIFT特征原理描述 1.SIFT综述 尺度不变特征转换(Scale-invariant feature transform或SIFT)是一种电脑视觉的算法用来侦测与描述 ...

  6. 局部图像描述子【计算机视觉第二章】

    目录 什么是局部图像描述子 Harris角点检测算法 角点(corner points): 角点特征: Harris 角点检测算子: Harris 角点检测算法的基本思想: Harris 角点检测算法 ...

  7. ehd边缘直方图描述子 matlab,第 2 章 局部图像描述子

    第 2 章 局部图像描述子 本章旨在寻找图像间的对应点和对应区域.本章将介绍用于图像匹配的两种局部描述子算法.本书的很多内容中都会用到这些局部特征,它们在很多应用中都有重要作用,比如创建全景图.增强现 ...

  8. 计算机视觉-局部图像描述子

    目录 一.Harris角点检测器 二.SLFT(尺度不变特征变换) 1.兴趣点 2.描述子 3.检测兴趣点 4.匹配描述子 三.匹配地理标记图像 不行我还是忍不住想吐槽:我使用的工具是pycharm, ...

  9. 计算机视觉学习2_局部图像描述子_SIFT算法_特征匹配_集美大学地标

    文章目录 相关环境的搭建 原理部分 Harris角点检测算法 SIFT(尺度不变特征变换) 尺度不变性 实验部分 Harris和sift特征匹配处理 结果对比 集美大学小地图 相关环境的搭建 1.PC ...

最新文章

  1. 海量数据处理:从并发编程到分布式系统
  2. CRC24循环冗余校验码的FPGA实现
  3. 软工作业3—词频统计
  4. Android 调用系统邮件,发送邮件到指定邮箱
  5. JavaScript学习随记——数组一
  6. C# winform 窗体怎么隐藏标题栏,不显示标题栏
  7. 陈年牵手徐静蕾之一箭双雕
  8. python的判断与循环
  9. Java Maven项目打包成可执行jar文件
  10. Java程序优化的一些最佳实践
  11. 英语口语中的音变现象及读音规则
  12. lumion实例渲染6.2
  13. 小程序:canvas绘制网络图片
  14. [USACO Section 4.4]追查坏牛奶Pollutant Control (最小割)
  15. springboot中static下的图片404
  16. 戴尔服务器r510怎么系统,DELLR510服务器上安系统.docx
  17. 一站式:虚拟机安装Linux系统(CentOS_7),多节点Linux环境打造,XShell的使用
  18. 我辞去高薪程序员工作,转行干淘宝,每天起床睁开眼,先赔几千!转行,你怕么?...
  19. Win7和Win10如何使文件的视图默认按详细信息显示
  20. 约8937亿元:台积电创下台湾企业市值最高纪录

热门文章

  1. 公共课-HTML基础
  2. java静态内部类单例模式
  3. Codeforces Round #262 (Div. 2) 460C. Present(二分)
  4. Unity自动滚动字幕的实现
  5. 【1080TI驱动+CUDA10.1+cudnn】安装记录
  6. “秘密”社交挖握人性罪恶过多必死
  7. 脚踝扭伤处理及恢复方法
  8. 互联网网站类型主要有哪些
  9. 聊聊开发中经历的几种后端语言
  10. ctp量化交易接口文档