Python计算机视觉:第二章 图像局部描述符
第二章 圖像局部描述符
這一章主要介紹兩種非常典型的、不同的圖像描述子,這兩種圖像描述子的使用將貫穿于本書,并且作為重要的局部特征,它們應用到了很多應用領域,比如創建全景圖、增強現實、3維重建等。
2.1 Harris角點檢測
Harris角點檢測算法是最簡單的角點檢測方法之一。關于harris算法的原理,可以參閱本書中譯本。下面是harris角點檢測實例代碼。
# -*- coding: utf-8 -*- from pylab import * from PIL import Image from PCV.localdescriptors import harris""" Example of detecting Harris corner points (Figure 2-1 in the book). """# 讀入圖像 im = array(Image.open('../data/empire.jpg').convert('L'))# 檢測harris角點 harrisim = harris.compute_harris_response(im)# Harris響應函數 harrisim1 = 255 - harrisimfigure() gray()#畫出Harris響應圖 subplot(141) imshow(harrisim1) print harrisim1.shape axis('off') axis('equal')threshold = [0.01, 0.05, 0.1] for i, thres in enumerate(threshold):filtered_coords = harris.get_harris_points(harrisim, 6, thres)subplot(1, 4, i+2)imshow(im)print im.shapeplot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')axis('off')#原書采用的PCV中PCV harris模塊 #harris.plot_harris_points(im, filtered_coords)# plot only 200 strongest # harris.plot_harris_points(im, filtered_coords[:200])show()運行上面代碼,可得原書P32頁的圖:在上面代碼中,先代開一幅圖像,將其轉換成灰度圖像,然后計算相響應函數,通過響應值選擇角點。最后,將這些檢測的角點在原圖上顯示出來。如果你想對角點檢測方法做一個概覽,包括想對Harris檢測器做些提高或改進,可以參閱WIKI中的例子WIKI.
2.1.2 在圖像間尋找對應點
Harris角點檢測器可以給出圖像中檢測到興趣點,但它并沒有提供在圖像間對興趣點進行比較的方法,我們需要在每個角點添加描述子,以及對這些描述子進行比較。關于興趣點描述子,見本書中譯本。下面再現原書P35頁中的結果:
# -*- coding: utf-8 -*- from pylab import * from PIL import Imagefrom PCV.localdescriptors import harris from PCV.tools.imtools import imresize""" This is the Harris point matching example in Figure 2-2. """# Figure 2-2上面的圖 #im1 = array(Image.open("../data/crans_1_small.jpg").convert("L")) #im2= array(Image.open("../data/crans_2_small.jpg").convert("L"))# Figure 2-2下面的圖 im1 = array(Image.open("../data/sf_view1.jpg").convert("L")) im2 = array(Image.open("../data/sf_view2.jpg").convert("L"))# resize加快匹配速度 im1 = imresize(im1, (im1.shape[1]/2, im1.shape[0]/2)) im2 = imresize(im2, (im2.shape[1]/2, im2.shape[0]/2))wid = 5 harrisim = harris.compute_harris_response(im1, 5) filtered_coords1 = harris.get_harris_points(harrisim, wid+1) d1 = harris.get_descriptors(im1, filtered_coords1, wid)harrisim = harris.compute_harris_response(im2, 5) filtered_coords2 = harris.get_harris_points(harrisim, wid+1) d2 = harris.get_descriptors(im2, filtered_coords2, wid)print 'starting matching' matches = harris.match_twosided(d1, d2)figure() gray() harris.plot_matches(im1, im2, filtered_coords1, filtered_coords2, matches) show()運行上面代碼,可得下圖:正如你從上圖所看到的,這里有很多錯配的。近年來,提高特征描述點檢測與描述有了很大的發展,在下一節我們會看這其中最好的算法之一——SIFT。
2.2 sift描述子
在過去的十年間,最成功的圖像局部描述子之一是尺度不變特征變換(SIFT),它是由David Lowe發明的。SIFT在2004年由Lowe完善并經受住了時間的考驗。關于SIFT原理的詳細介紹,可以參閱中譯本,在WIKI上你可以看一個簡要的概覽。
2.2.1 興趣點
2.2.2 描述子
2.2.3 檢測感興趣點
為了計算圖像的SIFT特征,我們用開源工具包VLFeat。用Python重新實現SIFT特征提取的全過程不會很高效,而且也超出了本書的范圍。VLFeat可以在www.vlfeat.org上下載,它的二進制文件可以用于一些主要的平臺。這個庫是用C寫的,不過我們可以利用它的命令行接口。此外,它還有Matlab接口。下面代碼是再現原書P40頁的代碼:
# -*- coding: utf-8 -*- from PIL import Image from pylab import * from PCV.localdescriptors import sift from PCV.localdescriptors import harris# 添加中文字體支持 from matplotlib.font_manager import FontProperties font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)imname = '../data/empire.jpg' im = array(Image.open(imname).convert('L')) sift.process_image(imname, 'empire.sift') l1, d1 = sift.read_features_from_file('empire.sift')figure() gray() subplot(131) sift.plot_features(im, l1, circle=False) title(u'SIFT特征',fontproperties=font) subplot(132) sift.plot_features(im, l1, circle=True) title(u'用圓圈表示SIFT特征尺度',fontproperties=font)# 檢測harris角點 harrisim = harris.compute_harris_response(im)subplot(133) filtered_coords = harris.get_harris_points(harrisim, 6, 0.1) imshow(im) plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*') axis('off') title(u'Harris角點',fontproperties=font)show()運行上面代碼,可得下圖:為了將sift和Harris角點進行比較,將Harris角點檢測的顯示在了圖像的最后側。正如你所看到的,這兩種算法選擇了不同的坐標。
2.2.4 描述子匹配
from PIL import Image from pylab import * import sys from PCV.localdescriptors import siftif len(sys.argv) >= 3:im1f, im2f = sys.argv[1], sys.argv[2] else: # im1f = '../data/sf_view1.jpg' # im2f = '../data/sf_view2.jpg'im1f = '../data/crans_1_small.jpg'im2f = '../data/crans_2_small.jpg' # im1f = '../data/climbing_1_small.jpg' # im2f = '../data/climbing_2_small.jpg' im1 = array(Image.open(im1f)) im2 = array(Image.open(im2f))sift.process_image(im1f, 'out_sift_1.txt') l1, d1 = sift.read_features_from_file('out_sift_1.txt') figure() gray() subplot(121) sift.plot_features(im1, l1, circle=False)sift.process_image(im2f, 'out_sift_2.txt') l2, d2 = sift.read_features_from_file('out_sift_2.txt') subplot(122) sift.plot_features(im2, l2, circle=False)#matches = sift.match(d1, d2) matches = sift.match_twosided(d1, d2) print '{} matches'.format(len(matches.nonzero()[0]))figure() gray() sift.plot_matches(im1, im2, l1, l2, matches, show_below=True) show()運行上面代碼,可得下圖:
2.3 地理標記圖像匹配
在結束本章前,我們看一個用局部描述子對地理標記圖像進行匹配的例子。
2.3.1 從Panoramio下載地理標記圖像
利用谷歌的圖片分享服務Panoramio,可以下載地理標記圖像。像很多其他的web服務一樣,Panoramio提供了API接口,通過提交HTTP GET請求url:
http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=public& from=0&to=20&minx=-180&miny=-90&maxx=180&maxy=90&size=medium上面minx、miny、maxx、maxy定義了獲取照片的地理區域。下面代碼是獲取白宮地理區域的照片實例:
# -*- coding: utf-8 -*- import json import os import urllib import urlparse from PCV.tools.imtools import get_imlist from pylab import * from PIL import Image#change the longitude and latitude here #here is the longitude and latitude for Oriental Pearl minx = '-77.037564' maxx = '-77.035564' miny = '38.896662' maxy = '38.898662'#number of photos numfrom = '0' numto = '20' url = 'http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=' + numfrom + '&to=' + numto + '&minx=' + minx + '&miny=' + miny + '&maxx=' + maxx + '&maxy=' + maxy + '&size=medium'#this is the url configured for downloading whitehouse photos. Uncomment this, run and see. #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)j = json.loads(c.read()) imurls = [] for im in j['photos']:imurls.append(im['photo_file_url'])for url in imurls:image = urllib.URLopener()image.retrieve(url, os.path.basename(urlparse.urlparse(url).path))print 'downloading:', url#顯示下載到的20幅圖像 figure() gray() filelist = get_imlist('./') for i, imlist in enumerate(filelist):im=Image.open(imlist)subplot(4,5,i+1)imshow(im)axis('off') show()譯者稍微修改了原書的代碼,上面numto是設置下載照片的數目。運行上面代碼可在腳本所在的目錄下得到下載到的20張圖片,代碼后面部分為譯者所加,用于顯示下載到的20幅圖像:現在我們便可以用這些圖片利用局部特征對其進行匹配了。
2.3.2 用局部描述子進行匹配
在下載完上面的圖片后,我們便可提取他們的描述子。這里,我們用前面用到的SIFT描述子。
# -*- coding: utf-8 -*- from pylab import * from PIL import Image from PCV.localdescriptors import sift from PCV.tools import imtools import pydot""" This is the example graph illustration of matching images from Figure 2-10. To download the images, see ch2_download_panoramio.py."""#download_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)download_path = "F:/dropbox/Dropbox/translation/pcv-notebook/data/panoimages" # set this to the path where you downloaded the panoramio images path = "F:/dropbox/Dropbox/translation/pcv-notebook/data/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_matchesmatchscores[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 diagonalmatchscores[j, i] = matchscores[i, j]上面將兩兩進行特征匹配后的匹配數保存在matchscores中,最后一部分將矩陣填充完整,它并不是必須的,原因是該“距離度量”矩陣是對稱的。運行上面代碼,可得到下面的結果:
662 0 0 2 0 0 0 0 1 0 0 1 2 0 3 0 19 1 0 2 0 901 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 2 0 0 266 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 2 1 0 1481 0 0 2 2 0 0 0 2 2 0 0 0 2 3 2 0 0 0 0 0 1748 0 0 1 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 1747 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 0 0 555 0 0 0 1 4 4 0 2 0 0 5 1 0 0 1 0 2 1 0 0 2206 0 0 0 1 0 0 1 0 2 0 1 1 1 1 0 0 0 1 0 0 629 0 0 0 0 0 0 0 1 0 0 20 0 0 0 0 0 0 0 0 0 829 0 0 1 0 0 0 0 0 0 2 0 0 0 0 0 0 1 0 0 0 1025 0 0 0 0 0 1 1 1 0 1 1 0 2 0 0 4 1 0 0 0 528 5 2 15 0 3 6 0 0 2 0 0 2 0 0 4 0 0 1 0 5 736 1 4 0 3 37 1 0 0 0 1 0 2 0 0 0 0 0 0 2 1 620 1 0 0 1 0 0 3 0 0 0 0 0 2 1 0 0 0 15 4 1 553 0 6 9 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2273 0 1 0 0 19 0 0 2 0 0 0 2 1 0 1 3 3 0 6 0 542 0 0 0 1 0 0 3 0 1 5 0 0 0 1 6 37 1 9 1 0 527 3 0 0 1 0 2 0 1 1 1 0 0 1 0 1 0 1 0 0 3 1139 0 2 2 0 0 1 0 0 1 20 2 0 0 0 0 0 0 0 0 0 499注意:這里譯者為排版美觀起見,用的是原書運行的結果,上面代碼時間運行的結果跟原書得到的結果是有差異的。
2.3.3 可視化接連的圖片
這節我們對上面匹配后的圖像進行連接可視化,要做到這樣,我們需要在一個圖中用邊線表示它們之間是相連的。我們采用pydot工具包,它提供了GraphViz graphing庫的Python接口。不要擔心,它們安裝起來很容易。
Pydot很容易使用,下面代碼演示創建一個圖:
import pydotg = pydot.Dot(graph_type='graph')g.add_node(pydot.Node(str(0), fontcolor='transparent')) for i in range(5):g.add_node(pydot.Node(str(i + 1)))g.add_edge(pydot.Edge(str(0), str(i + 1)))for j in range(5):g.add_node(pydot.Node(str(j + 1) + '0' + str(i + 1)))g.add_edge(pydot.Edge(str(j + 1) + '0' + str(i + 1), str(j + 1))) g.write_png('../images/ch02/ch02_fig2-9_graph.png', prog='neato')運行上面代碼,在images/ch02/下生成一幅名字為ch02fig2-9graph的圖,如下所示:現在,我們回到那個地理圖像的例子,我們同樣將匹配后對其進行可視化。為了是得到的可視化結果比較好看,我們對每幅圖像用100*100的縮略圖縮放它們。
# -*- coding: utf-8 -*- from pylab import * from PIL import Image from PCV.localdescriptors import sift from PCV.tools import imtools import pydot""" This is the example graph illustration of matching images from Figure 2-10. To download the images, see ch2_download_panoramio.py."""#download_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)download_path = "F:/dropbox/Dropbox/translation/pcv-notebook/data/panoimages" # set this to the path where you downloaded the panoramio images path = "F:/dropbox/Dropbox/translation/pcv-notebook/data/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_matchesmatchscores[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 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 graphfor 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 sizeg.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 sizeg.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')運行上面代碼,可以得到下面的結果:正如上圖所示,我們可以看到三組圖像,前兩組是白宮不同的側面圖片。上面這個例子只是一個利用局部描述子進行匹配的很簡單的例子,我們并沒有對匹配進行核實,在后面兩個章節中,我們便可以對其進行核實了。
from:?http://yongyuan.name/pcvwithpython/chapter2.html
總結
以上是生活随笔為你收集整理的Python计算机视觉:第二章 图像局部描述符的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python计算机视觉:第一章 图像处理
- 下一篇: Python计算机视觉:第六章 图像聚类