Skip to content

Commit

Permalink
change sift to Lowe's SIFT
Browse files Browse the repository at this point in the history
  • Loading branch information
carpedm20 committed Dec 3, 2014
1 parent 149c449 commit 79e277b
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 31 deletions.
50 changes: 29 additions & 21 deletions 4_svm.py
Expand Up @@ -19,40 +19,26 @@

train_images, train_labels, test_images, test_labels = get_train_test(TEST)

def classify_svm(train_features, train_labels, test_features):
global SAVE
clf = svm.SVC(C = 0.005, kernel = 'linear', )
clf.fit(train_features, train_labels)

if not TEST and SAVE:
save_pickle("svm", clf)

return clf.predict(test_features)

def classify_logistic(train_features, train_labels, test_features):
global SAVE
clf = LogisticRegression()
clf.fit(train_features, train_labels)

if not TEST and SAVE:
save_pickle("logistic", clf)

return clf.predict(test_features)

pool = Pool(cv2.getNumberOfCPUs())

train_sift_with_null = pool.map(get_sift, train_images)
test_sift_with_null = pool.map(get_sift, test_images)

pool.terminate()

train_sift = removing_null(train_sift_with_null, train_labels)
reduced_train_sift = np.concatenate(train_sift, axis = 0)

test_sift_with_null = pool.map(get_sift, test_images)
test_sift = removing_null(test_sift_with_null, test_labels)
reduced_test_sift = np.concatenate(test_sift, axis = 0)

print "\n [*] Kmeans fitting"
start = timeit.default_timer()
k = 1000

nfeatures = reduced_train_sift.shape[0]
k = int(sqrt(nfeatures))

if False:
kmeans = KMeans(n_clusters = k,
init ='k-means++',
Expand Down Expand Up @@ -83,6 +69,28 @@ def classify_logistic(train_features, train_labels, test_features):
train_hist_features = get_histogram(k, train_sift, train_predicted)
test_hist_features = get_histogram(k, test_sift, test_predicted)


def classify_svm(train_features, train_labels, test_features):
global SAVE
clf = svm.SVC(C = 0.005, kernel = 'linear', )
clf.fit(train_features, train_labels)

if not TEST and SAVE:
save_pickle("svm", clf)

return clf.predict(test_features)

def classify_logistic(train_features, train_labels, test_features):
global SAVE
clf = LogisticRegression()
clf.fit(train_features, train_labels)

if not TEST and SAVE:
save_pickle("logistic", clf)

return clf.predict(test_features)


print "\n [*] Classifying SVM"
result = []
start = timeit.default_timer()
Expand Down
2 changes: 2 additions & 0 deletions 5_color.py
Expand Up @@ -45,6 +45,8 @@ def classify_logistic(train_features, train_labels, test_features):
train_hist = pool.map(get_color_histogram, train_images)
test_hist = pool.map(get_color_histogram, test_images)

pool.terminate()

print "\n ["+PREFIX+"][*] Classifying SVM"
result = []
start = timeit.default_timer()
Expand Down
Binary file added sift
Binary file not shown.
202 changes: 202 additions & 0 deletions sift.py
@@ -0,0 +1,202 @@
"""
Python module for use with David Lowe's SIFT code available at:
http://www.cs.ubc.ca/~lowe/keypoints/
adapted from the matlab code examples.
Jan Erik Solem, 2009-01-30
http://www.janeriksolem.net/2009/02/sift-python-implementation.html
"""

import os
import subprocess
from PIL import Image
from numpy import *
import numpy
import cPickle
import pylab
from os.path import exists
MAXSIZE = 1024
VERBOSE = True
WRITE_VERBOSE = False # no verbose reading atm


def process_image(imagename, resultname='temp.sift', dense=False):
""" process an image and save the results in a .key ascii file"""
print "working on ", imagename
if dense == False:
if imagename[-3:] != 'pgm':
#create a pgm file, image is resized, if it is too big.
# sift returns an error if more than 8000 features are found
size = (MAXSIZE, MAXSIZE)
im = Image.open(imagename).convert('L')
im.thumbnail(size, Image.ANTIALIAS)
im.save('tmp.pgm')
imagename = 'tmp.pgm'

#check if linux or windows
if os.name == "posix":
cmmd = "./sift < " + imagename + " > " + resultname
else:
cmmd = "siftWin32 < " + imagename + " > " + resultname

# run extraction command
returnvalue = subprocess.call(cmmd, shell=True)
if returnvalue == 127:
os.remove(resultname) # removing empty resultfile created by output redirection
raise IOError("SIFT executable not found")
if returnvalue == 2:
os.remove(resultname) # removing empty resultfile created by output redirection
raise IOError("image " + imagename + " not found")
if os.path.getsize(resultname) == 0:
raise IOError("extracting SIFT features failed " + resultname)

else:
import vlfeat

# defines how dense the grid is
size = (150, 150)
step = 10

im = Image.open(imagename).resize(size, Image.ANTIALIAS)
im_array = numpy.asarray(im)
if im_array.ndim == 3:
im_gray = vlfeat.vl_rgb2gray(im_array)
elif im_array.ndim == 2:
im_gray = im_array
else:
raise IOError("Not enough dims found in image " + resultname)


locs, int_descriptors = vlfeat.vl_dsift(im_gray, step=step, verbose=VERBOSE)
nfeatures = int_descriptors.shape[1]
padding = numpy.zeros((2, nfeatures))
locs = numpy.vstack((locs, padding))
header = ' '.join([str(nfeatures), str(128)])
temp = int_descriptors.astype('float') # convert descriptors to float
descriptors = temp[:]
with open(resultname, 'wb') as f:
cPickle.dump([locs.T, descriptors.T], f, protocol=cPickle.HIGHEST_PROTOCOL)
print "features saved in", resultname
if WRITE_VERBOSE:
with open(resultname, 'w') as f:
f.write(header)
f.write("\n")
for i in range(nfeatures):
f.write(' '.join(map(str, locs[:, i])))
f.write("\n")
f.write(' '.join(map(str, descriptors[:, i])))
f.write("\n")


def read_features_from_file(filename='temp.sift', dense=False):
""" read feature properties and return in matrix form"""

if exists(filename) != False | os.path.getsize(filename) == 0:
raise IOError("wrong file path or file empty: "+ filename)
if dense == True:
with open(filename, 'rb') as f:
locs, descriptors = cPickle.load(f)
else:
f = open(filename, 'r')
header = f.readline().split()

num = int(header[0]) # the number of features
featlength = int(header[1]) # the length of the descriptor
if featlength != 128: # should be 128 in this case
raise RuntimeError('Keypoint descriptor length invalid (should be 128).')

locs = zeros((num, 4))
descriptors = zeros((num, featlength));

#parse the .key file
e = f.read().split() # split the rest into individual elements
pos = 0
for point in range(num):
#row, col, scale, orientation of each feature
for i in range(4):
locs[point, i] = float(e[pos + i])
pos += 4

#the descriptor values of each feature
for i in range(featlength):
descriptors[point, i] = int(e[pos + i])
#print descriptors[point]
pos += 128

#normalize each input vector to unit length
descriptors[point] = descriptors[point] / linalg.norm(descriptors[point])
#print descriptors[point]

f.close()

return locs, descriptors



def match(desc1, desc2):
""" for each descriptor in the first image, select its match to second image
input: desc1 (matrix with descriptors for first image),
desc2 (same for second image)"""

dist_ratio = 0.6
desc1_size = desc1.shape

matchscores = zeros((desc1_size[0], 1))
desc2t = desc2.T # precompute matrix transpose
for i in range(desc1_size[0]):
dotprods = dot(desc1[i, :], desc2t) # vector of dot products
dotprods = 0.9999 * dotprods
#inverse cosine and sort, return index for features in second image
indx = argsort(arccos(dotprods))

#check if nearest neighbor has angle less than dist_ratio times 2nd
if arccos(dotprods)[indx[0]] < dist_ratio * arccos(dotprods)[indx[1]]:
matchscores[i] = indx[0]

return matchscores


def plot_features(im, locs):
""" show image with features. input: im (image as array),
locs (row, col, scale, orientation of each feature) """

pylab.gray()
pylab.imshow(im)
pylab.plot([p[1] for p in locs], [p[0] for p in locs], 'ob')
pylab.axis('off')
pylab.show()


def appendimages(im1, im2):
""" return a new image that appends the two images side-by-side."""

#select the image with the fewest rows and fill in enough empty rows
rows1 = im1.shape[0]
rows2 = im2.shape[0]

if rows1 < rows2:
im1 = concatenate((im1, zeros((rows2 - rows1, im1.shape[1]))), axis=0)
else:
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 a figure with lines joining the accepted matches in im1 and im2
input: im1,im2 (images as arrays), locs1,locs2 (location of features),
matchscores (as output from 'match'). """

im3 = appendimages(im1, im2)

pylab.gray()
pylab.imshow(im3)

cols1 = im1.shape[1]
for i in range(len(matchscores)):
if matchscores[i] > 0:
pylab.plot([locs1[i, 1],
locs2[int(matchscores[i]), 1] + cols1],
[locs1[i, 0], locs2[int(matchscores[i]), 0]],
'c')
pylab.axis('off')
pylab.show()
29 changes: 19 additions & 10 deletions utils.py
@@ -1,6 +1,7 @@
import numpy as np
import cv2
import cPickle
from os.path import exists, isdir, basename, join, splitext

from glob import glob
from random import shuffle
Expand All @@ -20,20 +21,28 @@ def get_color_histogram(img):
color = ('b','g','r')
for i, col in enumerate(color):
hist = cv2.calcHist([raw],[i],None,[256],[0,255])
#hist = cv2.calcHist([raw],[i],None,[4],[0,255])
cv2.normalize(hist,hist,0,255,cv2.NORM_MINMAX)
hists.append(np.int32(np.around(hist)).reshape((len(hist),)))
return np.concatenate(hists, axis = 0)

def get_sift(img):
raw = cv2.imread(img)
gray = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY)
#sift = cv2.SURF()
sift = cv2.SIFT()
"""sift = cv2.SIFT(nfeatures=1000,
nOctaveLayers=3,
contrastThreshold=0.04,
edgeThreshold=5)"""
kp, desc = sift.detectAndCompute(gray, None)
def get_sift(img, is_lowe=True):
if is_lowe:
features_fname = img + '.sift'
if exists(features_fname) == False:
sift.process_image(img, features_fname)
locs, desc = sift.read_features_from_file(features_fname)

else:
raw = cv2.imread(img)
gray = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY)
#sift = cv2.SURF()
sift = cv2.SIFT()
"""sift = cv2.SIFT(nfeatures=1000,
nOctaveLayers=3,
contrastThreshold=0.04,
edgeThreshold=5)"""
kp, desc = sift.detectAndCompute(gray, None)
#print img, gray.shape, len(kp), desc.shape
return desc

Expand Down

0 comments on commit 79e277b

Please sign in to comment.