2021-03-28

Posted 差不多女生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-03-28相关的知识,希望对你有一定的参考价值。

[计算机视觉]匹配地理标记图像

一、sift原理

SIFT算法概述

尺度不变特征转换即SIFT (Scale-invariant feature transform)是一种计算机视觉的算法。它用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。 其应用范围包含物体辨识、机器人地图感知与导航、影像缝合、3D模型建立、手势辨识、影像追踪和动作比对。SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。

Sfit特征提取和匹配具体步骤

  1. 生成高斯差分金字塔(DOG金字塔),尺度空间构建

  2. 空间极值点检测(关键点的初步查探)

  3. 稳定关键点的精确定位

  4. 关键点描述

  5. 特征点匹配
    示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

**

生成高斯差分金字塔(DOG金字塔),尺度空间构建

**

主要思想是通过对原始图像进行尺度变换,获得图像多尺度下的尺度空间表示序列,对这些序列进行尺度空间主轮廓的提取,并以该主轮廓作为一种特征向量,实现边缘、角点检测不同分辨率上的关键点提取等。

各尺度下图像的模糊度逐渐变大,能够模拟人在距离目标由近到远时目标物体在视网膜上的形成过程。

为了在尺度空间中找到稳定不变的极值点,在SIFT算法中使用了高斯差分(DOG)函数D(x,y,σ)D(x,y,σ),定义为
D(x,y,σ)=[G(x,y,kσ)−G(x,y,σ)]∗I(x,y)
=L(x,y,kσ)−L(x,y,σ)
其中 kσkσ和 σσ是连续的两个图像的平滑尺度,所得到的差分图像再高斯差分金字塔中

高斯模糊——降低图像中的噪点,强调了图像的重要特征。进行高斯模糊之和,纹理和次要细节将从图像中删除,并且保留形状和边缘之类的相关信息。

实现DOG——初始图像与不同σ值的高斯函数卷积,得到一垛模糊后图像,然后将这一垛图像临近两两相减得到对应的DOG。一副图像可以产生几组图像,一组图像包括几层图像。s为每组层数一般为3~5层,最后可以将s和k的关系确立为k=2^(1/s)

**尺度空间检测极值点

**——DOG上某个像素要和本尺度的8个像素以及上下相邻尺度各9个相邻像素共26个像素值进行比较,以确定是否为局部最大或最小值。如果它是相邻像素中最高或者最低的像素,则确定该像素点是尺度空间的极值点之一。

*稳定关键点的精确定位

DOG值对噪声和边缘比较敏感,所以在第2步的尺度空间中检测到的局部极值点还要经过进一步的筛选,去除不稳定和错误检测出的极值点,另一点就是在构建高斯金字塔过程中采用了下采样的图像,在下采样图像中提取的极值点对应在原始图像中的确切位置,也是要在本步骤中解决的问题。

关键点描述*

兴趣点(关键点)位置描述子给出兴趣点的位置 和尺度信息,为了实现旋转不变性,基于每个点周围图像梯度的方向和大小,sift描述算子使用主方向描述参考方向,主方向使用直方图来衡量。sift描述算子在每个像素点附近选取子区域网格,在每个子区域计算图像梯度方向直方图,拼接起来组成描述算子向量。sift描述算子是由44个子区域,每个子区域有8个方向,会产生128个小区间直方图(448=128)也就是一张图像的每一个像素点都有128维的特征向量来唯一标识,即使方向有变换,也可以通过主方向来同步变换达到旋转不变性。

David G.Lowed的实验结果表明:对每个关键点,采用4
4*8共128维向量的描述子进项关键点表征,综合效果最佳:

特征点匹配

分别对模板图(参考图)和实时图(观测图)建立关键点描述子集合。目标的识别是通过两点集内关键点描述子的比对来完成具有128维的关键点描述子的相似性度量采用欧式距离。

sift特征点提取和匹配


```python
from pylab import *
from PIL import Image
from numpy import *
import os


def process_image(imagename, resultname, params="--edge-thresh 10 --peak-thresh 5"):
    """处理一幅图像,然后将结果保存在文件中"""

    if imagename[-3:] != 'pgm':
        # 创建一个pgm文件
        im = 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 plot_features(im, locs, circle=False):
    """显示带有特征的图像
        输入:im(数组图像),locs(每个特征的行、列、尺度和方向角度)"""

    def draw_circle(c,r):
        t = arange(0,1.01,.01)*2*pi
        x = 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')
    return

def match(desc1, desc2):
    """对于第一幅图像的每个描述子,选取其在第二幅图像中的匹配
        输入: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.6
    desc1_size = desc1.shape

    matchscores = zeros((desc1_size[0],1), 'int')
    desc2t = desc2.T    #预先计算矩阵转置
    for i in range(desc1_size[0]):
        dotprods = dot(desc1[i,:], desc2t) #向量点乘
        dotprods = 0.9999*dotprods
        # 反余弦和反排序,返回第二幅图像中特征的索引
        index = argsort(arccos(dotprods))

        # 检查最近邻的角度是否小于dist_ratio乘以第二近邻的角度
        if arccos(dotprods)[index[0]] < dist_ratio * arccos(dotprods)[index[1]]:
            matchscores[i] = int(index[0])

    return matchscores

def match_twosided(desc1,decs2):
    """双向对称版本的match"""

    matches_12 = match(desc1, decs2)
    matches_21 = match(decs2, decs2)

    ndx_12 = matches_12.nonzero()[0]

    # 去除不对称匹配
    for n in ndx_12:

        if matches_21[int(matches_12[n])] != n:
            matches_12[n] = 0

    return matches_12

def appendimages(im1, im2):
    """返回将两幅图像并排拼接成的一幅新图像"""

    # 选取具有最少行数的图像,然后填充足够的空行
    row1 = im1.shape[0]
    row2 = im2.shape[0]

    if row1 < row2:
        im1 = concatenate((im1,zeros((row2-row1,im1.shape[1]))), axis=0)
    elif row1 > row2:
        im2 = concatenate((im2,zeros((row1-row2,im2.shape[1]))), axis=0)

    # 如果这些情况都没有,那么他们的行数相同,不需要进行填充

    return concatenate((im1,im2), axis=1)

def plot_matches(im1, im2, locs1, locs2, matchscores, show_below=True):
    """显示一幅带有连接匹配之间连线的图片
        输入:im1,im2(数组图像),locs1,locs2(特征位置),matchscores(match的输出),
        show_below(如果图像应该显示再匹配下方)"""

    im3 = appendimages(im1,im2)
    if show_below:
        im3 = vstack((im3,im3))

    imshow(im3)

    cols1 = im1.shape[1]
    for i in range(len(matchscores)):
        if matchscores[i] > 0:
            plot([locs1[i, 0], locs2[matchscores[i, 0], 0] + cols1], [locs1[i, 1], locs2[matchscores[i, 0], 1]], 'c')
    axis('off')

if __name__ == '__main__':
    # imname = 'xqimage08.jpg'
    # im1 = array(Image.open(imname).convert('L'))
    # process_image(imname, 'xqimage08.sift')
    # l1, d1 = read_features_from_file('xqimage08.sift')
    #
    # figure()
    # gray()
    # plot_features(im1, l1, circle=True)
    # show()

    im1f = r'p1.jpg'
    im2f = r'p6.jpg'
    im1 = array(Image.open(im1f))
    im2 = array(Image.open(im2f))

    process_image(im1f, 'jimei-sift2.sift')
    l1, d1 = read_features_from_file('jimei-sift2.sift')
    figure()
    gray()
    subplot(121)
    plot_features(im1, l1, circle=False)

    process_image(im2f, 'jimei-sift2.sift')
    l2, d2 = read_features_from_file('jimei-sift2.sift')
    subplot(122)
    plot_features(im2, l2, circle=False)

    matches = match_twosided(d1, d2)
    print(' matches'.format(len(matches.nonzero()[0])))
    figure()
    gray()
    plot_matches(im1, im2, l1, l2, matches, show_below=True)
    show()

原图:
p1:
p2:

结果截图:

得到的结论;
发现sift更适用于图像特征检测,旋转不变性较强、可以解决一些光线和亮度问题,且比harris灵活、匹配准确些。虽然sift算法能够解决旋转角度、光线亮度问题,但是也不是十分准确,对于旋转角度过大和光线亮度反差很大时,也会出现错误点匹配(甚至会出现找不到特征点),从图中匹配的结果看出来sift算法对旋转角度匹配点也不是很多。

二、地理标记特征匹配

代码:

# -*- coding: utf-8 -*-
import json
import os
import urllib
from pylab import *
from PIL import Image
from PCV.localdescriptors import sift
from PCV.tools import imtools
import pydot

if __name__ == '__main__':
    download_path = "C:\\Users\\17912\\PycharmProjects\\untitled"
    path = "C:\\Users\\17912\\PycharmProjects\\untitled"

    imlist = imtools.get_imlist(download_path)
    nbr_images = len(imlist)

    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 triangle
            print('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 diagonal
            matchscores[j, i] = matchscores[i, j]

    # 可视化

    threshold = 2  # min number of matches needed to create link

    g = 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 pair
                im = Image.open(imlist[i])
                im.thumbnail((100, 100))
                filename = path + str(i) + '.jpg'
                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 pair
                im = Image.open(imlist[j])
                im.thumbnail((100, 100))
                filename = path + str(j) + '.jpg'
                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_jpg('p1.jpg')

结果截图:

实验过程遇到的问题:
1、图片太大而报出too many indices for array
解决方法:把所需要匹配的图像裁剪或压缩调整图片的大小(注意匹配照片的大小要一致)
2.生成不了sift文件
解决方法:需要下载安装graphviz和pydot,并且要下载pcv到site-packages中并修改sift.py文件中的cmm路径.

以上是关于2021-03-28的主要内容,如果未能解决你的问题,请参考以下文章

SIFT算法原理-极值点的精确定位

SIFT特征描述与检测的Matlab实现

SIFT特征描述与检测的Matlab实现

SIFT特征描述与检测的Matlab实现

SIFT特征描述与检测的Matlab实现

斑点检测(LoG,DoG)(下)