2014년 11월 30일 일요일

Python에서 sqlite를 이용한 BoVW 구현

# Python에서 sqlite를 이용한 BoVW 구현
# funMV, 2014.12
from numpy import *
import pickle
from pysqlite2 import dbapi2 as sqlite
import sift
import imagesearch


f = open("ukbench/first1000/list.txt",'r') # to access sub-directory
lines = f.readlines() # read all lines through line to line style
f.close()
imlist=[ 'ukbench/first1000/'+line[:-1] for line in lines] # to eliminate last character '\n'

nbr_images=len(imlist)
featlist=[ imlist[i][:-3]+'sift' for i in range(nbr_images)] # filename.sift in each line




# load vocabulary
with open('vocabulary.pkl','rb') as f:
    voc = pickle.load(f)


# create db
con = sqlite.connect('test1.db') # 재 실행시, 반드시 test1.db를 지우고 돌려야 함 
                             # 일단, 실행되면 hdd에 test1.db가 저장되기 때문


# create tables
con.execute('create table imlist(filename)')
con.execute('create table imwords(imid,wordid,vocname)')
con.execute('create table imhistograms(imid,histogram,vocname)')      

# 다음 4개 명령은 없어도 실행되지만 좀 느려지는 것 같음 
con.execute('create index im_idx on imlist(filename)')
con.execute('create index wordid_idx on imwords(wordid)')
con.execute('create index imid_idx on imwords(imid)')
con.execute('create index imidhist_idx on imhistograms(imid)')

con.commit()




# test db
locs, descr = sift.read_features_from_file(featlist[0])
# locs=2276x4, descr=2276x128
# For first image, 2277 features are there and they will be prjected to vw


imwords=voc.project(descr)
#voc.shape[0]=498: # of visual words
#imwords.shape=498의 히스토그램(보팅) 정보
#imwords: voting number of features per each word (histogram). some features among 2278 features
# are voted 7 times to first word, and 6 times for second words of vw, so on. 
#array([  7.,   6.,   2.,   1.,   5.,   4.,   4.,   1.,   0.,   4.,   2.,
#         3.,   6.,   1.,   2.,   4.,   2.,   0.,   1.,   9.,   1.,   1.,
#         2.,   3.,   0.,   1.,   7.,   3.,   2.,   7.,   3.,   0.,   5.,
#        17.,   1.,   3.,  16.,   6.,   3.,   8.,  26.,  11.,   1.,  10.,
#         3.,   3.,   4.,   2.,   2.,   1.,   2.,   1.,   2.,   2.,  ...
nbr_words=imwords.shape[0] # 498  



# 위는 test모드이고 여기서부터는 실제 모든 im의 feature들을 db에 삽입 
# go through all images, project features on vocabulary and insert
for i in range(nbr_images)[:100]: # [0,1,2,...,98,99]
    locs, descr = sift.read_features_from_file(featlist[i])
    imname = imlist[i]

    imwords=voc.project(descr)
    nbr_words=imwords.shape[0]

    # (1) 파일 이름을 db에 저장
    cur=con.execute("insert into imlist(filename) values ('%s')" %imname)
    imid = cur.lastrowid

    # (2) 파일 이름 id - 각 word에 대한 voting 횟수 연계 저장
    for j in range(nbr_words):
        word = imwords[j]
        con.execute("insert into imwords(imid,wordid,vocname) values (?,?,?)",
                    (imid,word,voc.name))

    # (3) 파일이름 id와 히스토그램 전체 저장    
    con.execute("insert into imhistograms(imid,histogram,vocname) values (?,?,?)",
                (imid,pickle.dumps(imwords),voc.name))



# 여기서 최종 결과를 저장하고 나가려면 commit를 해 주여야 함.
# con.commit()
# 다시 사용 시
# con=sqlite.connect('test1.db')




# Test for saved db
print con.execute('select count (filename) from imlist').fetchone()
# (100,), 100개의 im name이 저장

print con.execute('select * from imlist').fetchone()
# (u'ukbench/first1000/ukbench00000.jpg',)





##################################################
# 여기서 부터 저장된 db를 이용한 test
##################################################

# test할 query인 첫번째 im의 id, 히스토그램을 가져옴
im_id = con.execute("select rowid from imlist where filename='%s'" % imlist[0]).fetchone()
#im_id=(1,)
s = con.execute("select histogram from imhistograms where rowid='%d'" % im_id).fetchone()
h = pickle.loads(str(s[0])) # len(.)=498, histogram for word voting



#Using the index to get candidates
#locs, descr = sift.read_features_from_file(featlist[0])
#imwords=voc.project(descr)
#words=imwords.nonzero()[0] #voting이 하나라도 있는 words의 index



words=h.nonzero()[0]
#vw에 대한 histogram(bin수는 보팅 횟수가 0인 빈을 배제 후 vw의 갯수 만큼)
# words.shape=(455,)=[0,1,2,3,5,....]


# find candidates
candidates = []
for word in words:
    # table imword에서 word id로 imid를 추출. 즉, 특정 word를 가진 모든 im의 id를 추출
    # 즉, query im의 해당 word를 가지는 db내 모든 im의 id 리스트를 candidates에 저장
    im_ids = con.execute("select distinct imid from imwords where wordid=%d"
                % word).fetchall()
    c = [i[0] for i in im_ids]
    candidates += c


 
# len(candidates) = 1443 




# take all unique words and reverse sort on occurrence 
tmp = [(w,candidates.count(w)) for w in set(candidates)]
# candidates.count(1)=23, candidates.count(10)=15
# set(candidates)=[1,2,3,4,...,99,100]
# tmp=[(1, 23), (2, 23), (3, 19), (4, 26), (5, 11), (6, 13), (7, 14),
#  (8, 11), (9, 28), (10, 15), (11, 14), (12, 30), (13, 10),.....
# (95, 27), (96, 31), (97, 19), (98, 16), (99, 18), (100, 17)]
tmp.sort(cmp=lambda x,y:cmp(x[1],y[1]))
tmp.reverse()
candi=[w[0] for w in tmp] # len(candi)=100
#candi=[43,77,44,42,78,79,...,21,84,83]
#필요한 것은 im의 id이므로 sort후 reverse해줌 



matchscores=[]
for imid in candi:
    s = con.execute("select histogram from imhistograms where rowid='%d'" % imid).fetchone()
    cand_h = pickle.loads(str(s[0])) # histogram for word voting

    cand_dist = sqrt( sum( voc.idf*(h-cand_h)**2 ) )
    matchscores.append( (cand_dist,imid) )


matchscores.sort()
print matchscores[:10]
#[(0.0, 1), (60.812088499474271, 2), (61.547483004618186, 3), (92.620967753952812, 4),
# (100.59065889285603, 34), (107.76370948763174, 28), (108.27892205906744, 25),
# (109.39719124624605, 9), (110.33866766043165, 10), (110.77231202013482, 20)]

    

con.commit()
con.close()









Bag of Visual Words


Bag of Words의 요약:




# BoW를 이해하기 위한 Toy example
# BoW algorithm analysis
# 2013/06/28, 2014/12/03 개선
# by funmv 
#
from PIL import Image
from pylab import *
import os
from numpy import *
from scipy.cluster.vq import *
import sift
import vocabulary


# 물체의 class는 3개이다 (즉, 0~3/4~7/8~11의 4개씩 동일 물체를 다른 자세에서 찍었음. 아래 그림 참조)
imlist = ['ukbench00000.jpg', 'ukbench00001.jpg', 'ukbench00002.jpg', 'ukbench00003.jpg', 'ukbench00004.jpg', 'ukbench00005.jpg', 'ukbench00006.jpg', 'ukbench00007.jpg', 'ukbench00008.jpg', 'ukbench00009.jpg', 'ukbench00010.jpg', 'ukbench00011.jpg']

nbr_images=len(imlist)
featlist=[ imlist[i][:-3]+'sift' for i in range(nbr_images)]

"""for i in range(nbr_images):
    sift.process_image(imlist[i], featlist[i])
"""

descr = []
descr.append(sift.read_features_from_file(featlist[0])[1])
descriptors = descr[0]
# sift.read_features_from_file(featlist[i])[0]:
# list of [pixel coord of each feature point, scale, rotation angle] for i-image
# size: (# of feature point x 4) for i-th image
#
# sift.read_features_from_file(featlist[i])[1]:
# list of [feature values] for i-th image
# size: (# of feature point x 128) for i-th image

for i in arange(1, nbr_images):
    descr.append(sift.read_features_from_file(featlist[i])[1])
    descriptors = vstack((descriptors, descr[i])) # stack of vector

#len(descr[0]): number of feature points -> 2276
#len(descr[0][1]): size of 1st feature vector -> 128
    
voc, distortion = kmeans(descriptors[::10,:],3,1) # select one per 10 rows, 3개의 word를 뽑아냄

len(voc) #3, voc = 3x128
len(voc[0]) #3
len(voc[1]) #128

nbr_words = voc.shape[0] #3

# (# of images, bins of histogram(= # of words))
#    = (12x3)
imwords=zeros((nbr_images, nbr_words)) 
print imwords

words, distance = vq(descr[0],voc) # vector quantization
# len(words)->2276
# words: index vector of the cluster that each feature involves
#        [1, 2, 1, 0, 1, 2, ...]

#voca = vocabulary.Vocabulary('ukbenchtest')

for i in range(nbr_images): # def project
    hist = zeros((nbr_words))
    words, distance = vq(descr[i],voc) 
    # 현재 im에 대해 각 feature가 속하는 word의 index와 이 word까지의 거리가 리턴
    # index를 이용하여 해당 word에 보팅하여 histogram을 만듬 
    for w in words:
        hist[w] += 1
    imwords[i] = hist

print imwords # degree that each im involve to each cluster


"""
     0      1     2    : cluster index (word가 3개이니까 index는 2까지)  
[[  766.   461.  1049.]: 1st image의 histogram의 모양
 [  725.   451.  1020.]: 2nd image의 "
 [  671.   461.  1133.]: ...
 [ 1101.   630.  1403.]
 [  260.   317.   409.]
 [  267.   308.   370.]
 [  283.   394.   476.]
 [  239.   331.   410.]
 [ 1105.   468.  1317.]
 [  116.   191.   390.]
 [  122.   251.   439.]
 [ 1183.   597.  1475.]]:  12번째 im의 histogram모양
  12번째 이미지의 모든 특징 중에서 word 0에 속하는 것은 1183개, 1번 597개, 2번 1475개이다.  3경우 합하면 특징의 개수이다.  따라서 test영상의 특징에 대한 histogram을 그리고 위 12개 중에서 hist모양이 비슷한 것을 찾으면 그것이 해당 영상이다. 
 """








   

 

 

 


다음의 코드에서 voc의 내용을 알 수 있음.