Skip to content

Commit f41d89d

Browse files
committed
Dump of book code and initial examples.
1 parent b05df57 commit f41d89d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+4725
-0
lines changed

LICENSE.txt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2012, Jan Erik Solem
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
1. Redistributions of source code must retain the above copyright notice, this
8+
list of conditions and the following disclaimer.
9+
2. Redistributions in binary form must reproduce the above copyright notice,
10+
this list of conditions and the following disclaimer in the documentation
11+
and/or other materials provided with the distribution.
12+
13+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

PCV/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from PCV.classifiers import *
2+
from PCV.clustering import *
3+
from PCV.geometry import *
4+
from PCV.imagesearch import *
5+
from PCV.localdescriptors import *
6+
from PCV.tools import *

PCV/__init__.pyc

337 Bytes
Binary file not shown.

PCV/classifiers/__init__.py

Whitespace-only changes.

PCV/classifiers/__init__.pyc

148 Bytes
Binary file not shown.

PCV/classifiers/bayes.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from numpy import *
2+
3+
4+
class BayesClassifier(object):
5+
6+
def __init__(self):
7+
""" Initialize classifier with training data. """
8+
9+
self.labels = [] # class labels
10+
self.mean = [] # class mean
11+
self.var = [] # class variances
12+
self.n = 0 # nbr of classes
13+
14+
def train(self,data,labels=None):
15+
""" Train on data (list of arrays n*dim).
16+
Labels are optional, default is 0...n-1. """
17+
18+
if labels==None:
19+
labels = range(len(data))
20+
self.labels = labels
21+
self.n = len(labels)
22+
23+
for c in data:
24+
self.mean.append(mean(c,axis=0))
25+
self.var.append(var(c,axis=0))
26+
27+
def classify(self,points):
28+
""" Classify the points by computing probabilities
29+
for each class and return most probable label. """
30+
31+
# compute probabilities for each class
32+
est_prob = array([gauss(m,v,points) for m,v in zip(self.mean,self.var)])
33+
34+
print 'est prob',est_prob.shape,self.labels
35+
# get index of highest probability, this gives class label
36+
ndx = est_prob.argmax(axis=0)
37+
38+
est_labels = array([self.labels[n] for n in ndx])
39+
40+
return est_labels, est_prob
41+
42+
43+
def gauss(m,v,x):
44+
""" Evaluate Gaussian in d-dimensions with independent
45+
mean m and variance v at the points in (the rows of) x.
46+
http://en.wikipedia.org/wiki/Multivariate_normal_distribution """
47+
48+
if len(x.shape)==1:
49+
n,d = 1,x.shape[0]
50+
else:
51+
n,d = x.shape
52+
53+
# covariance matrix, subtract mean
54+
S = diag(1/v)
55+
x = x-m
56+
# product of probabilities
57+
y = exp(-0.5*diag(dot(x,dot(S,x.T))))
58+
59+
# normalize and return
60+
return y * (2*pi)**(-d/2.0) / ( sqrt(prod(v)) + 1e-6)
61+
62+
63+

PCV/classifiers/knn.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from numpy import *
2+
3+
class KnnClassifier(object):
4+
5+
def __init__(self,labels,samples):
6+
""" Initialize classifier with training data. """
7+
8+
self.labels = labels
9+
self.samples = samples
10+
11+
def classify(self,point,k=3):
12+
""" Classify a point against k nearest
13+
in the training data, return label. """
14+
15+
# compute distance to all training points
16+
dist = array([L2dist(point,s) for s in self.samples])
17+
18+
# sort them
19+
ndx = dist.argsort()
20+
21+
# use dictionary to store the k nearest
22+
votes = {}
23+
for i in range(k):
24+
label = self.labels[ndx[i]]
25+
votes.setdefault(label,0)
26+
votes[label] += 1
27+
28+
return max(votes)
29+
30+
31+
def L2dist(p1,p2):
32+
return sqrt( sum( (p1-p2)**2) )
33+
34+
def L1dist(v1,v2):
35+
return sum(abs(v1-v2))

PCV/clustering/__init__.py

Whitespace-only changes.

PCV/clustering/__init__.pyc

147 Bytes
Binary file not shown.

PCV/clustering/hcluster.py

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from numpy import *
2+
from itertools import combinations
3+
4+
5+
class ClusterNode(object):
6+
def __init__(self,vec,left,right,distance=0.0,count=1):
7+
self.left = left
8+
self.right = right
9+
self.vec = vec
10+
self.distance = distance
11+
self.count = count # only used for weighted average
12+
13+
def extract_clusters(self,dist):
14+
""" Extract list of sub-tree clusters from
15+
hcluster tree with distance<dist. """
16+
if self.distance < dist:
17+
return [self]
18+
return self.left.extract_clusters(dist) + self.right.extract_clusters(dist)
19+
20+
def get_cluster_elements(self):
21+
""" Return ids for elements in a cluster sub-tree. """
22+
return self.left.get_cluster_elements() + self.right.get_cluster_elements()
23+
24+
def get_height(self):
25+
""" Return the height of a node,
26+
height is sum of each branch. """
27+
return self.left.get_height() + self.right.get_height()
28+
29+
def get_depth(self):
30+
""" Return the depth of a node, depth is
31+
max of each child plus own distance. """
32+
return max(self.left.get_depth(), self.right.get_depth()) + self.distance
33+
34+
def draw(self,draw,x,y,s,imlist,im):
35+
""" Draw nodes recursively with image
36+
thumbnails for leaf nodes. """
37+
38+
h1 = int(self.left.get_height()*20 / 2)
39+
h2 = int(self.right.get_height()*20 /2)
40+
top = y-(h1+h2)
41+
bottom = y+(h1+h2)
42+
43+
# vertical line to children
44+
draw.line((x,top+h1,x,bottom-h2),fill=(0,0,0))
45+
46+
# horizontal lines
47+
ll = self.distance*s
48+
draw.line((x,top+h1,x+ll,top+h1),fill=(0,0,0))
49+
draw.line((x,bottom-h2,x+ll,bottom-h2),fill=(0,0,0))
50+
51+
# draw left and right child nodes recursively
52+
self.left.draw(draw,x+ll,top+h1,s,imlist,im)
53+
self.right.draw(draw,x+ll,bottom-h2,s,imlist,im)
54+
55+
56+
class ClusterLeafNode(object):
57+
def __init__(self,vec,id):
58+
self.vec = vec
59+
self.id = id
60+
61+
def extract_clusters(self,dist):
62+
return [self]
63+
64+
def get_cluster_elements(self):
65+
return [self.id]
66+
67+
def get_height(self):
68+
return 1
69+
70+
def get_depth(self):
71+
return 0
72+
73+
def draw(self,draw,x,y,s,imlist,im):
74+
nodeim = Image.open(imlist[self.id])
75+
nodeim.thumbnail([20,20])
76+
ns = nodeim.size
77+
im.paste(nodeim,[int(x),int(y-ns[1]//2),int(x+ns[0]),int(y+ns[1]-ns[1]//2)])
78+
79+
80+
def L2dist(v1,v2):
81+
return sqrt(sum((v1-v2)**2))
82+
83+
84+
def L1dist(v1,v2):
85+
return sum(abs(v1-v2))
86+
87+
88+
def hcluster(features,distfcn=L2dist):
89+
""" Cluster the rows of features using
90+
hierarchical clustering. """
91+
92+
# cache of distance calculations
93+
distances = {}
94+
95+
# initialize with each row as a cluster
96+
node = [ClusterLeafNode(array(f),id=i) for i,f in enumerate(features)]
97+
98+
while len(node)>1:
99+
closest = float('Inf')
100+
101+
# loop through every pair looking for the smallest distance
102+
for ni,nj in combinations(node,2):
103+
if (ni,nj) not in distances:
104+
distances[ni,nj] = distfcn(ni.vec,nj.vec)
105+
106+
d = distances[ni,nj]
107+
if d<closest:
108+
closest = d
109+
lowestpair = (ni,nj)
110+
ni,nj = lowestpair
111+
112+
# average the two clusters
113+
new_vec = (ni.vec + nj.vec) / 2.0
114+
115+
# create new node
116+
new_node = ClusterNode(new_vec,left=ni,right=nj,distance=closest)
117+
node.remove(ni)
118+
node.remove(nj)
119+
node.append(new_node)
120+
121+
return node[0]
122+
123+
124+
from PIL import Image,ImageDraw
125+
126+
def draw_dendrogram(node,imlist,filename='clusters.jpg'):
127+
""" Draw a cluster dendrogram and save to a file. """
128+
129+
# height and width
130+
rows = node.get_height()*20
131+
cols = 1200
132+
133+
# scale factor for distances to fit image width
134+
s = float(cols-150)/node.get_depth()
135+
136+
# create image and draw object
137+
im = Image.new('RGB',(cols,rows),(255,255,255))
138+
draw = ImageDraw.Draw(im)
139+
140+
# initial line for start of tree
141+
draw.line((0,rows/2,20,rows/2),fill=(0,0,0))
142+
143+
# draw the nodes recursively
144+
node.draw(draw,20,(rows/2),s,imlist,im)
145+
im.save(filename)
146+
im.show()

PCV/geometry/__init__.py

Whitespace-only changes.

PCV/geometry/__init__.pyc

145 Bytes
Binary file not shown.

PCV/geometry/camera.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from numpy import *
2+
from scipy import linalg
3+
4+
5+
class Camera(object):
6+
""" Class for representing pin-hole cameras. """
7+
8+
def __init__(self,P):
9+
""" Initialize P = K[R|t] camera model. """
10+
self.P = P
11+
self.K = None # calibration matrix
12+
self.R = None # rotation
13+
self.t = None # translation
14+
self.c = None # camera center
15+
16+
17+
def project(self,X):
18+
""" Project points in X (4*n array) and normalize coordinates. """
19+
20+
x = dot(self.P,X)
21+
for i in range(3):
22+
x[i] /= x[2]
23+
return x
24+
25+
26+
def factor(self):
27+
""" Factorize the camera matrix into K,R,t as P = K[R|t]. """
28+
29+
# factor first 3*3 part
30+
K,R = linalg.rq(self.P[:,:3])
31+
32+
# make diagonal of K positive
33+
T = diag(sign(diag(K)))
34+
if linalg.det(T) < 0:
35+
T[1,1] *= -1
36+
37+
self.K = dot(K,T)
38+
self.R = dot(T,R) # T is its own inverse
39+
self.t = dot(linalg.inv(self.K),self.P[:,3])
40+
41+
return self.K, self.R, self.t
42+
43+
44+
def center(self):
45+
""" Compute and return the camera center. """
46+
47+
if self.c is not None:
48+
return self.c
49+
else:
50+
# compute c by factoring
51+
self.factor()
52+
self.c = -dot(self.R.T,self.t)
53+
return self.c
54+
55+
56+
57+
# helper functions
58+
59+
def rotation_matrix(a):
60+
""" Creates a 3D rotation matrix for rotation
61+
around the axis of the vector a. """
62+
R = eye(4)
63+
R[:3,:3] = linalg.expm([[0,-a[2],a[1]],[a[2],0,-a[0]],[-a[1],a[0],0]])
64+
return R
65+
66+
67+
def rq(A):
68+
from scipy.linalg import qr
69+
70+
Q,R = qr(flipud(A).T)
71+
R = flipud(R.T)
72+
Q = Q.T
73+
74+
return R[:,::-1],Q[::-1,:]

0 commit comments

Comments
 (0)