计算机视觉——图像地理位置标记

图像分类

       图片地理标记即图像分类,可以实现多张图片进行特定的标志性物体分类。主要步骤需要对图像提取局部描述算子,一般情况都是使用SIFT特征描述算子。然后通过判断图像是否具有匹配的局部描述算子来定义图像之间的连接,实现图像可视化连接,图的边代表连接。在实现图像连接将会使用pydot工具包,该工具包是功能强大的GraphViz图形库的Python接口。

(一)安装graphviz     

      首先下载安装graphviz-2.38.msi,再运行命令pip install pydot,最后可在系统路径PATH中添加graphviz的路径:C:\Program Files (x86)\Graphviz2.38\bin。(注意:graphviz安装路径可以随便存。pydot的Node节点添加图片时,图片的路径需要为绝对路径,且分隔符为/ 

下载连接:https://graphviz.gitlab.io/_pages/Download/Download_windows.html

双击graphviz-2.38进行安装。

点next安装成功过后,就要把路径添加到环境变量path里。具体步骤:此电脑-->属性-->高级系统设置-->环境变量-->path,然后新建添加其路径:E:\360Downloads\Graphviz2.38\bin

窗口键+R输入cmd,在出现的命令窗口输入:pip install pydot

 

完成以上步骤,环境配置就基本成功了。

 

 

(二)图片分类实现

   具体实现时,要先创建一个sift.py文件,然后把要分类的图片都存在该项目下(注意:所有图片之间像素不要相差太大,最好可以用美图秀秀批处理进行以同一宽度自适应高度生成图片),就可以直接运行一下代码:

# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from numpy import *
import os
import pydot
import sift

def get_imlist(path):
    return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]


# pydot需要绝对路径,路径分隔符为/而非\
download_path = "E:/Python37_course/test"
path = "E:/Python37_course/test/"

# list of downloaded filenames
imlist = 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 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
print ("The match scores is: \n", matchscores)

# 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 craete 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:
            #图像对中的第一幅图像
            im = Image.open(imlist[i])
            im.thumbnail((100,100))
            filename = path + str(i) + '.png'
            im.save(filename) #需要一定大小的临时文件
            g.add_node(pydot.Node(str(i), fontcolor='transparent',
                       shape='rectangle', image=filename))

            #图像对中的第二幅图像
            im = Image.open(imlist[j])
            im.thumbnail((100,100))
            filename = path + str(j) + '.png'
            im.save(filename) #需要一定大小的临时文件
            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')

sift.py文件

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


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 write_featrues_to_file(filename, locs, desc):
    """将特征位置和描述子保存到文件中"""
    savetxt(filename, hstack((locs,desc)))

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')



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
        # 反余弦和反排序,返回第二幅图像中特征的索引
        indx = argsort(arccos(dotprods))

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

    return matchscores 


def match_twosided(desc1, desc2):
    """双向对称版本的match()"""
    matches_12 = match(desc1, desc2)
    matches_21 = match(desc2, desc1)

    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):
    """返回将两幅图像并排拼接成的一幅新图像"""
    #选取具有最少行数的图像,然后填充足够的空行
    rows1 = 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)
    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),title('SIFT特征匹配')

    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')

运行代码:

如果出现:

因为我是一次就运行成功,没有遇到错误。(1)出现没有生成PNG图片错误,一般都是路径配置错误;所以路径加入path环境变量的时候一定要加到:系统变量的path里。

提示:在sift特征方法里我用的vlfeat是0.9.20版本,(2)如果出现IndexError :too many indices for array错误,可以尝试换vlfeat是0.9.17版本.

(3)如果还出现sift描述算子的.sift找不到错误,可以查看这篇相关博文连接:https://blog.csdn.net/weixin_43837871/article/details/88604483

(三)图像分类结果展现

下图是项目文件夹:

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值