vlfeat/ 0000755 0001750 0001750 00000000000 12570775755 010771 5 ustar dima dima vlfeat/apps/ 0000755 0001750 0001750 00000000000 12570775230 011720 5 ustar dima dima vlfeat/apps/recognition/ 0000755 0001750 0001750 00000000000 12570775230 014240 5 ustar dima dima vlfeat/apps/recognition/trainEncoder.m 0000644 0001750 0001750 00000014122 12420040400 017005 0 ustar dima dima function encoder = trainEncoder(images, varargin) % TRAINENCODER Train image encoder: BoVW, VLAD, FV % ENCODER = TRAINENCOER(IMAGES) trains a BoVW encoder from the % specified list of images IMAGES. % % TRAINENCODER(..., 'OPT', VAL, ...) accepts the following options: % % Type:: 'bovw' % Bag of visual words ('bovw'), VLAD ('vlad') or Fisher Vector % ('fv'). % % numPcaDimension:: +inf % Use PCA to reduce the descriptor dimensionality to this % dimension. Use +inf to deactivate PCA. % % Whitening:: false % Set to true to divide the principal components by the % corresponding standard deviation s_i. % % WhiteningRegul:: 0 % When using whitening, divide by s_max * WhiteningRegul + s_i % instead of s_i alone. % % Renormalize:: false % If true, descriptors are L2 normalized after PCA or % whitening. % % % Subdivisions:: [] % A list of spatial subdivisions. Each column is a rectangle % [XMIN YMIN XMAX YMAX]. The spatial subdivisions are % % Layouts:: {'1x1'} % A list of strings representing regular spatial subdivisions % in the format MxN, where M is the number of vertical % subdivisions and N the number of horizontal ones. For % example {'1x1', 2x2'} uses 5 partitions: the whole image and % four quadrants. The subdivisions are appended to the ones % specified by the SUBDIVISIONS option. % % ReadImageFn:: @readImage % The function used to load an image. % % ExtractorFn:: @getDenseSIFT % The function used to extract the feature frames and % descriptors from an image. % Author: Andrea Vedaldi % Copyright (C) 2013 Andrea Vedaldi % All rights reserved. % % This file is part of the VLFeat library and is made available under % the terms of the BSD license (see the COPYING file). opts.type = 'bovw' ; opts.numWords = [] ; opts.seed = 1 ; opts.numPcaDimensions = +inf ; opts.whitening = false ; opts.whiteningRegul = 0 ; opts.numSamplesPerWord = [] ; opts.renormalize = false ; opts.layouts = {'1x1'} ; opts.geometricExtension = 'none' ; opts.subdivisions = zeros(4,0) ; opts.readImageFn = @readImage ; opts.extractorFn = @getDenseSIFT ; opts.lite = false ; opts = vl_argparse(opts, varargin) ; for i = 1:numel(opts.layouts) t = sscanf(opts.layouts{i},'%dx%d') ; m = t(1) ; n = t(2) ; [x,y] = meshgrid(... linspace(0,1,n+1), ... linspace(0,1,m+1)) ; x1 = x(1:end-1,1:end-1) ; y1 = y(1:end-1,1:end-1) ; x2 = x(2:end,2:end) ; y2 = y(2:end,2:end) ; opts.subdivisions = cat(2, opts.subdivisions, ... [x1(:)' ; y1(:)' ; x2(:)' ; y2(:)'] ) ; end if isempty(opts.numWords) switch opts.type case {'bovw'} opts.numWords = 1024 ; case {'fv'} opts.numWords = 64 ; opts.numPcaDimensions = 80 ; case {'vlad'} opts.numWords = 64 ; opts.numPcaDimensions = 100 ; opts.whitening = true ; opts.whiteninRegul = 0.01 ; otherwise assert(false) ; end end if isempty(opts.numSamplesPerWord) switch opts.type case {'bovw'} opts.numSamplesPerWord = 200 ; case {'vlad','fv'} opts.numSamplesPerWord = 1000 ; otherwise assert(false) ; end if opts.lite opts.numSamplesPerWord = 10 ; end end disp(opts) ; encoder.type = opts.type ; encoder.subdivisions = opts.subdivisions ; encoder.readImageFn = opts.readImageFn ; encoder.extractorFn = opts.extractorFn ; encoder.numWords = opts.numWords ; encoder.renormalize = opts.renormalize ; encoder.geometricExtension = opts.geometricExtension ; %% Step 0: obtain sample image descriptors numImages = numel(images) ; numDescrsPerImage = ceil(opts.numWords * opts.numSamplesPerWord / numImages) ; parfor i = 1:numImages fprintf('%s: reading: %s\n', mfilename, images{i}) ; im = encoder.readImageFn(images{i}) ; w = size(im,2) ; h = size(im,1) ; features = encoder.extractorFn(im) ; randn('state',0) ; rand('state',0) ; sel = vl_colsubset(1:size(features.descr,2), single(numDescrsPerImage)) ; descrs{i} = features.descr(:,sel) ; frames{i} = features.frame(:,sel) ; frames{i} = bsxfun(@times, bsxfun(@minus, frames{i}(1:2,:), [w;h]/2), 1./[w;h]) ; end descrs = cat(2, descrs{:}) ; frames = cat(2, frames{:}) ; %% Step 1 (optional): learn PCA projection if opts.numPcaDimensions < inf || opts.whitening fprintf('%s: learning PCA rotation/projection\n', mfilename) ; encoder.projectionCenter = mean(descrs,2) ; x = bsxfun(@minus, descrs, encoder.projectionCenter) ; X = x*x' / size(x,2) ; [V,D] = eig(X) ; d = diag(D) ; [d,perm] = sort(d,'descend') ; d = d + opts.whiteningRegul * max(d) ; m = min(opts.numPcaDimensions, size(descrs,1)) ; V = V(:,perm) ; if opts.whitening encoder.projection = diag(1./sqrt(d(1:m))) * V(:,1:m)' ; else encoder.projection = V(:,1:m)' ; end clear X V D d ; else encoder.projection = 1 ; encoder.projectionCenter = 0 ; end descrs = encoder.projection * bsxfun(@minus, descrs, encoder.projectionCenter) ; if encoder.renormalize descrs = bsxfun(@times, descrs, 1./max(1e-12, sqrt(sum(descrs.^2)))) ; end %% Step 2 (optional): geometrically augment the features descrs = extendDescriptorsWithGeometry(opts.geometricExtension, frames, descrs) ; %% Step 3: learn a VQ or GMM vocabulary dimension = size(descrs,1) ; numDescriptors = size(descrs,2) ; switch encoder.type case {'bovw', 'vlad'} vl_twister('state', opts.seed) ; encoder.words = vl_kmeans(descrs, opts.numWords, 'verbose', 'algorithm', 'elkan') ; encoder.kdtree = vl_kdtreebuild(encoder.words, 'numTrees', 2) ; case {'fv'} ; vl_twister('state', opts.seed) ; if 1 v = var(descrs')' ; [encoder.means, encoder.covariances, encoder.priors] = ... vl_gmm(descrs, opts.numWords, 'verbose', ... 'Initialization', 'kmeans', ... 'CovarianceBound', double(max(v)*0.0001), ... 'NumRepetitions', 1) ; else addpath lib/yael/matlab [a,b,c] = ... yael_gmm(descrs, opts.numWords, 'verbose', 2) ; encoder.priors = single(a) ; encoder.means = single(b) ; encoder.covariances = single(c) ; end end vlfeat/apps/recognition/experiments.m 0000644 0001750 0001750 00000015371 12420040400 016742 0 ustar dima dima function experiments() % EXPERIMENTS Run image classification experiments % The experimens download a number of benchmark datasets in the % 'data/' subfolder. Make sure that there are several GBs of % space available. % % By default, experiments run with a lite option turned on. This % quickly runs all of them on tiny subsets of the actual data. % This is used only for testing; to run the actual experiments, % set the lite variable to false. % % Running all the experiments is a slow process. Using parallel % MATLAB and several cores/machiens is suggested. % Author: Andrea Vedaldi % Copyright (C) 2013 Andrea Vedaldi % All rights reserved. % % This file is part of the VLFeat library and is made available under % the terms of the BSD license (see the COPYING file). lite = true ; clear ex ; ex(1).prefix = 'fv-aug' ; ex(1).trainOpts = {'C', 10} ; ex(1).datasets = {'fmd', 'scene67'} ; ex(1).seed = 1 ; ex(1).opts = {... 'type', 'fv', ... 'numWords', 256, ... 'layouts', {'1x1'}, ... 'geometricExtension', 'xy', ... 'numPcaDimensions', 80, ... 'extractorFn', @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(1:-.5:-3))}; ex(2) = ex(1) ; ex(2).datasets = {'caltech101'} ; ex(2).opts{end} = @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(0:-.5:-3)) ; ex(3) = ex(1) ; ex(3).datasets = {'voc07'} ; ex(3).C = 1 ; ex(4) = ex(1) ; ex(4).prefix = 'vlad-aug' ; ex(4).opts = {... 'type', 'vlad', ... 'numWords', 256, ... 'layouts', {'1x1'}, ... 'geometricExtension', 'xy', ... 'numPcaDimensions', 100, ... 'whitening', true, ... 'whiteningRegul', 0.01, ... 'renormalize', true, ... 'extractorFn', @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(1:-.5:-3))}; ex(5) = ex(4) ; ex(5).datasets = {'caltech101'} ; ex(5).opts{end} = ex(2).opts{end} ; ex(6) = ex(4) ; ex(6).datasets = {'voc07'} ; ex(6).C = 1 ; ex(7) = ex(1) ; ex(7).prefix = 'bovw-aug' ; ex(7).opts = {... 'type', 'bovw', ... 'numWords', 4096, ... 'layouts', {'1x1'}, ... 'geometricExtension', 'xy', ... 'numPcaDimensions', 100, ... 'whitening', true, ... 'whiteningRegul', 0.01, ... 'renormalize', true, ... 'extractorFn', @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(1:-.5:-3))}; ex(8) = ex(7) ; ex(8).datasets = {'caltech101'} ; ex(8).opts{end} = ex(2).opts{end} ; ex(9) = ex(7) ; ex(9).datasets = {'voc07'} ; ex(9).C = 1 ; ex(10).prefix = 'fv' ; ex(10).trainOpts = {'C', 10} ; ex(10).datasets = {'fmd', 'scene67'} ; ex(10).seed = 1 ; ex(10).opts = {... 'type', 'fv', ... 'numWords', 256, ... 'layouts', {'1x1'}, ... 'geometricExtension', 'none', ... 'numPcaDimensions', 80, ... 'extractorFn', @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(1:-.5:-3))}; ex(11) = ex(10) ; ex(11).datasets = {'caltech101'} ; ex(11).opts{end} = @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(0:-.5:-3)) ; ex(12) = ex(10) ; ex(12).datasets = {'voc07'} ; ex(12).C = 1 ; ex(13).prefix = 'fv-sp' ; ex(13).trainOpts = {'C', 10} ; ex(13).datasets = {'fmd', 'scene67'} ; ex(13).seed = 1 ; ex(13).opts = {... 'type', 'fv', ... 'numWords', 256, ... 'layouts', {'1x1', '3x1'}, ... 'geometricExtension', 'none', ... 'numPcaDimensions', 80, ... 'extractorFn', @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(1:-.5:-3))}; ex(14) = ex(13) ; ex(14).datasets = {'caltech101'} ; ex(14).opts{6} = {'1x1', '2x2'} ; ex(14).opts{end} = @(x) getDenseSIFT(x, ... 'step', 4, ... 'scales', 2.^(0:-.5:-3)) ; ex(15) = ex(13) ; ex(15).datasets = {'voc07'} ; ex(15).C = 1 ; if lite, tag = 'lite' ; else, tag = 'ex' ; end for i=1:numel(ex) for j=1:numel(ex(i).datasets) dataset = ex(i).datasets{j} ; if ~isfield(ex(i), 'trainOpts') || ~iscell(ex(i).trainOpts) ex(i).trainOpts = {} ; end traintest(... 'prefix', [tag '-' dataset '-' ex(i).prefix], ... 'seed', ex(i).seed, ... 'dataset', char(dataset), ... 'datasetDir', fullfile('data', dataset), ... 'lite', lite, ... ex(i).trainOpts{:}, ... 'encoderParams', ex(i).opts) ; end end % print HTML table pf('
The latest version of VLFeat is %env:VERSION;. To use VLFeat, simply download and unpack the latest binary package and add the appropriate paths to your environment (see below for details).
Downloads |
Install |
VLFeat is under active development. You can browse our Git repository or download it by
(This will require Git to be installed). The top of the master branch corresponds to the most recent version of VLFeat, but it could be unstable.
We welcome contributions to both the documentation and the source
code of VLFeat. You can create patches against our Git repository and
send them to us for inclusion in the next version. There are two ways
to contribute. For minor changes, simply clone our public repository,
as explained above. Once you have made and committed your changes
locally, you can submit them to the project via e-mail using a command
like git format-patch
:
For major additions, we prefer to handle collaboration through github. Follow their tutorial to fork our project and submit your modifications using a pull request.
This page lists a number of example VLFeat applications. The code
can be found in the VLROOT/apps/
subdirectory in the
VLFeat package.
This sample application uses VLFeat to train an test an image classifier on the Caltech-101 data. The classifier achieves 65% average accuracy by using a single feature and 15 training images per class. It uses:
The program is fully contained in a single MATLAB M-file, and can also be simply adapted to use your own data (change conf.calDir).
This example application extends the Caltech-101 demo above in many
ways: it supports multiple encoding methods, including BoVW, VLAD, and
Fisher Vectors, tweaked image features, and multiple benchmark
datasets. The code is located int apps/recognition
. Start
from the main
file.
The following tables report results on a few standard benchmark datasets (PASCAL VOC 2007 classification challenge, Caltech 101 30 training images, MIT Scene 67, and Flickr Material Dataset) for a number of different encodings:
method | VOC07 | Caltech 101 | Scene 67 | FMD |
---|---|---|---|---|
FV | 59.12% mAP | 73.02% Acc | 58.25% Acc | 59.60% Acc |
FV + aug. | 60.25% mAP | 75.61% Acc | 57.57% Acc | 60.80% Acc |
FV + s.p. | 62.23% mAP | 77.63% Acc | 61.83% Acc | 60.80% Acc |
VLAD + aug. | 54.66% mAP | 78.68% Acc | 53.29% Acc | 49.40% Acc |
BOVW + aug. | 49.87% mAP | 75.98% Acc | 50.22% Acc | 46.00% Acc |
The baseline feature is SIFT (vl_dsift
) computed at
seven scales with a factor $\sqrt{2}$ between successive scales, bins
8 pixel wide, and computed with a step of 4 pixels. All experiments
but the Caltech-101 ones start by doubling the resolution of the input
image. The details of the encodings are as follows:
vl_vlad
).vl_fisher
).vl_svmtrain
). The parameter $C$ is set to 10 for all
dataset except PASCAL VOC, for which it is set to 1." + code + "") else: gen.putString("
" + code + "") DocNode.publish(self, gen, pageNode) publish = makeGuard(publish) # -------------------------------------------------------------------- class DocHtmlElement(DocNode): # -------------------------------------------------------------------- def __init__(self, tag, attrs, URL = None, locator = None): DocNode.__init__(self, attrs, URL, locator) self.tag = tag def __str__(self): str = "
vl_function
as links
gen.putString("/>")
text = "".join([y.text for y in walkNodes(self, DocHtmlText)])
ok = nodeIndex.has_key(text)
if ok: gen.putString("")
DocNode.publish(self, gen, pageNode)
if ok: gen.putString("")
gen.putString("")
gen.putString(self.tag)
gen.putString(">")
else:
gen.putString(">")
DocNode.publish(self, gen, pageNode)
gen.putString("")
gen.putString(self.tag)
gen.putString(">")
publish = makeGuard(publish)
# --------------------------------------------------------------------
class DocTemplate(DocNode):
# --------------------------------------------------------------------
def __init__(self, attrs, URL, locator):
DocNode.__init__(self, attrs, URL, locator)
# --------------------------------------------------------------------
class DocPageStyle(DocNode):
# --------------------------------------------------------------------
def __init__(self, attrs, URL, locator):
DocNode.__init__(self, attrs, URL, locator)
def publish(self, gen, pageNode = None):
return None
def expand(self, gen, pageNode = None):
sa = self.getAttributes()
if sa.has_key("href"):
gen.putString("\n")
else:
gen.putString("\n")
expand = makeGuard(expand)
# --------------------------------------------------------------------
class DocPageScript(DocNode):
# --------------------------------------------------------------------
def __init__(self, attrs, URL, locator):
DocNode.__init__(self, attrs, URL, locator)
def publish(self, gen, pageNode = None):
return None
def expand(self, gen, pageNode = None):
sa = self.getAttributes()
gen.putString("\n")
expand = makeGuard(expand)
# --------------------------------------------------------------------
class DocPage(DocNode):
# --------------------------------------------------------------------
counter = 0
def __init__(self, attrs, URL, locator):
DocNode.__init__(self, attrs, URL, locator)
DocPage.counter = 1 + DocPage.counter
self.templateID = "template.default"
self.name = "page%d" % DocPage.counter
self.title = "untitled"
self.hide = False
for k, v in self.attrs.items():
if k == 'src':
self.title = v
elif k == 'name':
self.name = v
elif k == 'id':
pass
elif k == 'title':
self.title = v
elif k == 'hide':
self.hide = (v.lower() == 'yes')
else:
raise DocError(
"web:page cannot have '%s' attribute" % k)
def __str__(self):
return DocNode.__str__(self) + ":These instructions show how to setup a basic VLFeat project with Apple Xcode. For the sake of simplicty, we create a command line tool written in C. However, these steps apply with minor modifications to other project types and to the C++ lanuage.
First, let us create a new project
called vlfeat-client
. Open Xcode and select File
> New Project > Command Line Utility > Standard Tool
and click Choose. Give a name to your project (in our
case vlfeat-client
), and click Save.
Now we need to add VLFeat to the C compiler include search
path. To do this, select the vlfeat-client
target and
open the information panel (the blue button,
or Command-i). Then select the Build panel, search for
the field Header Search Paths, and add
VLFeat root path (in our case this is
just ~/src/vlfeat
).
Next, we add the libvl.dylib
library file to the
project resources so that Xcode links against it. To do this, drag
and drop the libvl.dylib
file (in our example
~/src/vlfeat/bin/maci/libvl.dylib
) to the left panel and click
Add.
Next, edit the main.c
source file and type the following code:
If you try to build the project, it should compile without errors
(if you are using C++, do not forget to wrap the include
statements in a extern "C" {}
block). However, if you try
to run the program, it will fail, complaining that it cannot find the
library image.
The reason is that libvl.dylib
is compiled with the
library install_name
equal
to @loader_path/libvl.dylib
. This causes the run-time
loader to look for the library in the same directory of the
executable. There are two ways around this problem: The first is to
install the library in a standard location
(e.g. /usr/local/lib
) and use the otool
command to change the
library install_name
. The other is to simply copy
the libvl.dylib
file in the executable directory. Here we
demonstrate the second technique.
To copy libvl.dylib
in the executable directory, we
add a Copy Files build phase to the project. Right-click
the vlfeat-client
target in the project panel and select
Add > New Build Phase > New Copy Files Build
Phase. Select Destination: Executables. Then drag-and-drop
the libvl.dylib
item from the panel to the Copy
Files build phase.
Now rebuild the project, and run it. It should run correctly, and if you open the debugger console you should see this:
This section features a number of tutorials illustrating some of the algorithms implemented in VLFeat, roughly divided into visual features such as SIFT and Fisher vectors and statistical methods, such as K-means, GMMs, KDTrees, and SVMs.
Local features: the concept of frames (keypoints). An overview of the concept of feature frame used as geometric reference in feature detection.
Covariant detectors. An introduction to computing co-variant features like Harris-Affine.
Histogram of Oriented Gradients (HOG). Getting started with this ubiquitous representation for object recognition and detection.
Local Intensity Order Pattern (LIOP). Getting started with the LIOP descriptor as an alternative to SIFT in keypoint matching.
Maximally Stable Extremal Regions (MSER). Extracting MSERs from an image as an alternative covariant feature detector.
Image distance transform. Compute the image distance transform for fast part models and edge matching.
Fisher vector and VLAD encodings. Compute global image encodings by pooling local image features with Fisher vectors and VLAD.
GMM. Learn Gaussian Mixture Models using the Expectation Maximization algorithm.
k-means. Cluster features with k-means.
Agglomerative Information Bottleneck (AIB). Cluster discrete data based on the mutual information between the data and class labels.
Quick shift. An introduction which shows how to create superpixels using this quick mode seeking method.
SLIC. An introduction to SLIC superpixels.
Support Vector Machine (SVM). Learn a binary classifier and check its convergence by plotting various statistical information.
Forests of kd-trees. Approximate nearest neighbour queries in high dimensions using an optimized forest of kd-trees.
Plotting functions for rank evaluation. Learn how to plot ROC, DET, and precision-recall curves.
MATLAB Utilities. A list of useful MATLAB functions bundled with VLFeat.
Integer optimized k-means (IKM). VLFeat integeger-otpimized k-means implementation (obsolete).
Hierarchical k-means (HIKM). Create a fast k-means tree for integer data (obsolete).
These instructions explain how to use VLFeat from the command line (shell).
Download and unpack the latest
VLFeat binary distribution in a directory of your choice
(e.g. ~/src/vlfeat
). Let VLFEATROOT
denote
this directory.
The command line tools are located
in VLFEATROOT/bin/ARCH
. Here ARCH
denotes
the subdirectory relative to your architecture (e.g. mac
for Mac OS X PPC, maci
for Mac OS X
Intel, glnx86
for Linux, and so on). For the sake of
illustration, the following table gives the path to the SIFT feature
extraction program for the varius architectures:
Platform | ARCH |
Path to command |
---|---|---|
Windows 32 | win32 |
VLFEATROOT\bin\w32\sift.exe |
Windows 64 | win64 |
VLFEATROOT\bin\w64\sift.exe |
Mac Intel 32 | maci |
VLFEATROOT/bin/maci/sift |
Mac Intel 64 | maci64 |
VLFEATROOT/bin/maci64/sift |
Linux 32 | glnx86 |
VLFEATROOT/bin/glnx86/sift |
Linux 64 | glnxa64 |
VLFEATROOT/bin/glnxa64/sift |
All commands have a corresponding man page found
in VLFEATROOT/src
. For UNIX based systems, the man pages
can be viewed with the man
utility. For instance
It might be convenient to add VLFeat to the system search paths. In
Linux and Mac OS X this involves modifying the PATH
and MANPATH
environment variables. The exact details may
vary, but it should be enough to add the following to your
~/.bash_profile
:
Alternatively, you can copy the executables and man pages to appropriate system-wide directories.
In 2012 the development of VLFeat is
supported by the PASCAL Harvest programme. Several people have been
working in Oxford to add new functionalities to the library. Moreover,
leading researchers in computer vision were consulted as
advisors of the project. These
contributions will be made public in the next several weeks as the
code is tuned and finalised.
A particularly significant contribution is the creation of a new sub-project, VLBenchmakrs, for the evaluation of feature detectors and descriptors. VLBenchmarks is meant to provide a future-proof benchmarking suite. The first release includes reimplementations of standard feature benchmarks to replace ageing legacy code and a brand new benchmark. In the future, it will be used to deliver to the community new, modern benchmarks in a consistent and simple to use pacakge.
This page shows how to compile VLFeat MEX files for usage in GNU Octave (tested on version 3.6.4).
Make sure that the image
toolbox is installed in
Octave. This can be obtained, for example, by using
the pkg
builtin Octave command:
Unpack VLFeat and use the Makefile to compile the MEX files. To
instruct the Makefile to target Octave as well, specify the path to
the mkoctfile
command. For example,
if mkoctfile
is in your current path and VLFeat is
unpacked in VLFEATROOT
, the following should work:
After the MEX files are successfully compiled (look for them
into toolbox/mex/octave/
), you can start using VLFeat in
Octave in the same way as
MATLAB. Do not forget to use the vl_setup
command to
initalize the paths:
HTML tags). For instance | Bla bla bla | Code Code Code | | Code Code Code generates one paragraph followed by one verbatim section. """ import xml.dom.minidom import sys import os import re __mpname__ = 'MDocFormatter' __version__ = '0.1' __date__ = '2008-01-01' __description__ = 'MDoc formatting module' __long_description__ = __doc__ __license__ = 'BSD' __author__ = 'Andrea Vedaldi' # terminal class Terminal: def isa(self, classinfo): return isinstance(self, classinfo) # empty terminal class E (Terminal): pass # blank line class B (Terminal): content = "" # non-blank line class L (Terminal): indent = 0 # regular line class PL (L): pass # line with bullet class BL (L): bullet = None inner_indent = 0 # line with description class DL (L): pass # -------------------------------------------------------------------- def lex(line): # -------------------------------------------------------------------- """ Parse the string LINE to a terminal symbol. Each line corresponds to exactly one terminal type. Terminal types are the leaf of a hierarchy of types. """ # a blank line match = re.match(r"\s*\n?$", line) ; if match: return B() # a line of the type ' content::inner_content' match = re.match(r"(\s*)(.*)::(.*)\n?$", line) if match: x = DL() x.indent = len(match.group(1)) x.content = match.group(2) x.inner_content = match.group(3) return x # a line of the type ' - inner_contet' match = re.match(r"(\s*)([-\*#]\s*)(\S.*)\n?$", line) if match: x = BL() x.indent = len(match.group(1)) x.inner_content = match.group(3) x.bullet = match.group(2) x.inner_indent = x.indent + len(x.bullet) x.content = x.bullet + x.inner_content return x # a line of the type ' content' match = re.match(r"(\s*)(\S.*)\n?$", line) if match: x = PL() x.indent = len(match.group(1)) x.content = match.group(2) return x # -------------------------------------------------------------------- class Lexer(object): # -------------------------------------------------------------------- """ l = Lexer(LINES) parses the array of strings LINES. Lexer has a head pointing to the current line. The head can be controlled by the following methods: l.next() advances the head and fetches the next terminal. l.back() moves back the head. l.getpos() returns the head position. l.seek(POS) sets the head position to POS. """ def __init__(self, lines): self.tokens = [] self.pos = -1 for line in lines: self.tokens.append(lex(line)) def next(self): self.pos = self.pos + 1 if self.pos >= len(self.tokens): return E() else: return self.tokens [self.pos] def seek(self, pos): self.pos = pos def back(self): if self.pos >=0: self.pos -= 1 def rewrite(self, str): self.tokens [self.pos] = str ; def getpos(self): return self.pos def __str__(self): str = "" for i,t in enumerate(self.tokens): str += "%5d) %s %s\n" % (i, t.__class__.__name__,t.content) return str # -------------------------------------------------------------------- class Formatter: # -------------------------------------------------------------------- """ f = Formatter(LINES) parses the array of strings LINES. f = Formatter(LINES, FUNCS) takes the dictionary of functions FUNCS. Function names must be uppercase. The dictionary entries are used to cross link functions in the generated documentation. Formatter(LINES, FUNCS, LINKTYPE) produces links of the specified type. Use 'a' for HTML anchors and 'wiki' for MediaWiki style links. f.toDOM() process the data to construct an XML (HTML) representation of them. """ def __init__ (self, lines, funcs={}, linktype='a'): self.indentinit = 0 lineone = lines[0] while lineone.startswith(' '): lineone = lineone[1:] self.indentinit += 1 self.tokens = Lexer(lines) self.xmldoc = xml.dom.minidom.Document() self.funcs = funcs self.linktype = linktype #print self.tokens def toTextNode(self,s): return self.xmldoc.createTextNode(unicode(s, 'iso-8859-1')) def addAttr(self, tag, attr, val): x = self.xmldoc.createAttribute(attr) x.nodeValue = val tag.setAttributeNode(x) def addText(self, tag, s): txt = self.toTextNode(s) tag.appendChild(txt) def addFancyText(self, tag, s): "Adds text while transforming function references to links." xs = [] last = -1 iter = re.finditer(r'(?:' r'(?P[A-Z][A-Z0-9_]*)' r'\([^\)]*\)' r')|(?:' r'' r'(?P [^<]*)' r' ' r')',s) # r'(?P[a-zA-Z0-9_]*)' # r')', s) # r')', s) for i in iter: func_name = i.group("function") page_name = i.group("page") if func_name and self.funcs.has_key(func_name.upper()): # retrieve function HTML location func_href = self.funcs[func_name.upper()] # add text so far xs.append(self.toTextNode(s[last+1:i.start()])) if self.linktype == 'a': # add link to function atag = self.xmldoc.createElement(u"a") self.addText(atag, i.group('function')) atag.setAttribute(u"href", u"%s" % (func_href)) xs.append(atag) elif self.linktype == 'wiki': linktxt = "[[%s|%s]]" % (func_href, i.group('function')) xs.append(self.toTextNode(linktxt)) # set head last = i.start()+len(i.group(1))-1 elif page_name: #print "page %s:" % page_name, i.group("text") page_href = "%%dox:%s;" % page_name # add text so far xs.append(self.toTextNode(s[last+1:i.start()])) if self.linktype == 'a': # add link to function atag = self.xmldoc.createElement(u"a") self.addText(atag, i.group('text')) atag.setAttribute(u"href", u"%s" % (page_href)) xs.append(atag) elif self.linktype == 'wiki': linktxt = "[[%s|%s]]" % (func_href, i.group('function')) xs.append(self.toTextNode(linktxt)) # set head last = i.end()-1 xs.append(self.toTextNode(s[last+1:])) for x in xs: tag.appendChild(x) # ................................................................ # E, B, L, PL, BL, DL, ... def parse_Terminal(self, T): "If the next terminal on the stream is of type T, the terminal" "is extracted and returned. Otherwise the function returns None" pos = self.tokens.getpos() t = self.tokens.next() if t.isa(T): return t self.tokens.seek(pos) return None # ................................................................ # DIV(N) -> (B | P(N) | BL(N) | DL(N) | V(N))+ def parse_DIV(self, indent): "Parse a DIV(N) symbol. A DIV(N) a sequence of blank" "lines (B or other blocks at indentation level N, such as" "pharagraphs P(N), bullet lists BL(N), description lists DN(N)" pos = self.tokens.getpos() xs = [] while True: x = self.parse_Terminal(B) if x: continue x = self.parse_P(indent) if x: xs.append(x) continue x = self.parse_V(indent) if x: xs.append(x) continue x = self.parse_UL(indent) if x: xs.append(x) continue x = self.parse_DL(indent) if x: xs.append(x) continue break if len(xs) == 0: return None return xs # ................................................................ # P(N) -> PL(N) L(N)* def parse_P(self, indent): content = "\n" good = False pos = self.tokens.getpos() # Introduced by PL x = self.parse_Terminal(PL) if x: if x.indent == indent: content += x.content + "\n" good = True else: self.tokens.back() if not good: return None # Continued by zero or more L while True: x = self.parse_Terminal(L) if x: if x.indent == indent: content += x.content + "\n" good = True continue else: self.tokens.back() break ptag = self.xmldoc.createElement("p") self.addFancyText(ptag, content) return ptag # ................................................................ # V(N) -> L(M)+, M > N def parse_V(self, indent): content = "\n" good = False pos = self.tokens.getpos() while True: x = self.parse_Terminal(L) if x: if x.indent > indent: content += " "*(x.indent - indent) + x.content + "\n" good = True continue else: self.tokens.back() x = self.parse_Terminal(B) if x: content += "\n" continue break if good: ptag = self.xmldoc.createElement("pre") # remove potential blank line at the end if content[-2:] == "\n\n": content= content[:-1] self.addText(ptag, content) return ptag self.tokens.seek(pos) return None # ................................................................ # UL(N) -> ULI(N)+ def parse_UL(self, indent): xs = [] while True: x = self.parse_ULI(indent) if x: xs.append(x) continue break if len(xs) == 0: return None ultag = self.xmldoc.createElement("ul") for x in xs: ultag.appendChild(x) return ultag # ................................................................ # ULI(N) -> UL(N,M) L(M)* DIV(M), M > N def parse_ULI(self, indent): content = "\n" good = False pos = self.tokens.getpos() # Introduced by UL x = self.parse_Terminal(BL) if x: if x.indent == indent: content += x.inner_content + "\n" indent = x.inner_indent good = True else: self.tokens.back() if not good: return None # Continued by zero or more L while True: x = self.parse_Terminal(L) if x: if x.indent == indent: content += x.content + "\n" good = True continue else: self.tokens.back() break litag = self.xmldoc.createElement(u"li") ptag = self.xmldoc.createElement(u"p") self.addFancyText(ptag, content) litag.appendChild(ptag) # Continued by DIV xs = self.parse_DIV(indent) if xs: for x in xs: litag.appendChild(x) return litag # ................................................................ # DL(N) -> DI(N)+ def parse_DL(self, indent): xs = [] while True: x = self.parse_DI(indent) if x: xs += x continue break if len(xs) == 0: return None dltag = self.xmldoc.createElement(u"dl") for x in xs: dltag.appendChild(x) return dltag # ................................................................ # DI(N) -> DL(N) DIV(M)?, M > N def parse_DI(self, indent): content = "\n" good = False pos = self.tokens.getpos() xs = [] # Introduced by DL x = self.parse_Terminal(DL) if x: if x.indent == indent: content += x.content + "\n" good = True else: self.tokens.back() if not good: return None if False: # adds text after :: as part of the description dd dttag = self.xmldoc.createElement(u"dt") dttxt = self.toTextNode(content) dttag.appendChild(dttxt) xs.append(dttag) # Inject inner_content c = x.inner_content.strip() if len(c) > 0: tk = PL() tk.content = x.inner_content t = self.tokens.next() self.tokens.back() if t.isa(L) and t.indent > indent: tk.indent = t.indent else: tk.indent = indent+1 ; self.tokens.rewrite(tk) self.tokens.back() else: # adds text after :: as part of the description term dt dttag = self.xmldoc.createElement(u"dt") dttxt = self.toTextNode(content) dttag.appendChild(dttxt) c = x.inner_content.strip() if len(c) > 0: deftag = self.xmldoc.createElement(u"span") self.addAttr(deftag, "class", "defaults") self.addText(deftag, c) dttag.appendChild(deftag) xs.append(dttag) # Continued by DIV t = self.tokens.next() self.tokens.back() if t.isa(L) and t.indent > indent: xs_ = self.parse_DIV(t.indent) if len(xs_) > 0: ddtag = self.xmldoc.createElement(u"dd") for x in xs_: ddtag.appendChild(x) xs.append(ddtag) return xs # ................................................................ def toDOM(self): # write xmf = self.xmldoc.createElement("div") xmf.setAttribute(u"class", u"documentation") self.xmldoc.appendChild(xmf) # parse documentation xs = self.parse_DIV(self.indentinit) for x in xs: xmf.appendChild(x) return self.xmldoc if __name__ == '__main__': text=""" Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. Also Fisher vectors. These are links BL(), BL(A,B) and BLA(A,A) (as long as the dictionary cites them). Mimamama verbatim1 verbatim2 verbatim3 verbatim4 verbatim5 Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. - outer1 / outer1 line 2 / outer1 line 3 / outer1 new paragarph - inner1 - inner2 - inner3 continued on next line continued with verbatim more verbatim after blank - inner4 - outer again - outer bla - list2 - list4 - BL() - BL(A,B) Test descrition:: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. Ancora:: Bli bli bli Blu blu blu - list - lust - last Bli bla Verbatimmo """ lines = text.splitlines() formatter = Formatter(lines, {'BL':'http://www.google.com'}, 'a') print formatter.toDOM().toxml("UTF-8") vlfeat/docsrc/doc.html 0000644 0001750 0001750 00000002335 12420040400 013642 0 ustar dima dima vlfeat/docsrc/install-matlab.html 0000644 0001750 0001750 00000004554 12420040400 016006 0 ustar dima dima The VLFeat reference documentation has three parts:
MATLAB functions
The reference documentation of VLFeat MATLAB commands (this is an on-line version of the documentation built in the command themsevles).
C API reference
This documentation includes descriptions of all the algorithms and hence it is useful even if you do not plan to use the C library directly.
Man pages
The documentation of the command line utilities bundled with VLFeat (this is an on-line version of the Unix man found in the
src/
subdirectory.In addition to the documentation, there are also tutorials which introduce many of the algorithms contained in the library.
vlfeat/docsrc/compiling.html 0000644 0001750 0001750 00000020152 12570775230 015101 0 ustar dima dima These instructions explain how to setup VLFeat in MATLAB (at least 2009B) using the binary distribution (it is also possible to compile the library and toolbox from source, including running on earlier MATLAB versions by disabling some features such as OpenMP support).
One-time setup
Download and unpack the latest VLFeat binary distribution in a directory of your choice (e.g.
~/src/vlfeat
). LetVLFEATROOT
denote this directory. VLFeat must be added to MATLAB search path by running thevl_setup
command found in theVLFEATROOT/toolbox
directory. From MATLAB prompt enter>> run('VLFEATROOT/toolbox/vl_setup') VLFeat 0.9.17 ready. To check that VLFeat is sucessfully installed, try to run the
vl_version
command:>> vl_version verbose VLFeat version 0.9.17 Static config: X64, little_endian, GNU C 40201 LP64, POSIX_threads, SSE2, OpenMP 4 CPU(s): GenuineIntel MMX SSE SSE2 SSE3 SSE41 SSE42 OpenMP: max threads: 4 (library: 4) Debug: yes SIMD enabled: yes Permanent setup
To permanently add VLFeat to your MATLAB environment, add this line to your
startup.m
file:run('VLFEATROOT/toolbox/vl_setup') When you restart MATLAB, you should see the VLFeat greeting message.
Getting started
All commands embed interface documentation that can be viewed with the builtin
help
command (e.g.help vl_sift
).VLFeat bundles a large number of demos. To use them, add the demo path with
vl_setup demo
. For example, a sift demovl_demo_sift_basic
can be run using the following:>> vl_setup demo >> vl_demo_sift_basic To see a list of demos TAB-complete
vl_demo
at MATLAB prompt, after runningvl_setup demo
.vlfeat/docsrc/tutorials/ 0000755 0001750 0001750 00000000000 12570775755 014274 5 ustar dima dima vlfeat/docsrc/tutorials/ikm.html 0000644 0001750 0001750 00000006255 12570775230 015736 0 ustar dima dima These instructions explain how to compile VLFeat from sources. While this is necessary in order to develop or modify VLFeat, using the pre-compiled binaries will work in most other cases.
VLFeat is largely self-contained and hence easy to compile. While certain features such as multi-core computation and vector instruction support may require specific compilers, most compilers and environments should be capable of producing fully functional version of the library. Compiling MATLAB or Octave support requires the corresponding applications to be installed too.
%tableofcontents; General instructions
Compiling for UNIX-like platforms (e.g. GNU/Linux, Mac OS X) assumes that the standard GNU toolchain is available. In particular, while compilers other than GCC can be used, the compilation scripts require GNU/make.
To compile the library, it is usually sufficient to change to VLFeat root directory, denoted
VLFEATROOT
in the following, and typemake
:$ cd VLFEATROOT $ make The make script attempts to automatically detect the host architecture and configure itself accordingly. If the architecture is not detected correctly, it can be specified manually. For instance
$ make ARCH=glnx86 compiles for GNU/Linux 32-bit.
make help
can be used to obtain a list of other useful options. You can also usemake info
to obtain a list of the configuration parameters used by the Makefile, which might allow you do debug any potential issue.Compiling MATLAB support
In order for MATLAB support to be compiled, the MATLAB
mex
script must be in the current path. If it is not, its location must be passed tomake
as follows. First, determine MATLAB's root directory by running a MATLAB session and issuing thematlabroot
command. LetMATLABROOT
denote the returned path (e.g./Applications/MATLAB_R2009b.app/
). Themex
script is usually located inMALTABROOT/bin/mex
. Then run the compilation with the command$ make MEX=MATLABROOT/bin/mex VLFeat must be compiled for the architecture used by MATLAB (run MATLAB's
computer
command to obtain this information). On Mac OS X it is often necessary to turn on 64-bit support explicitly by settingARCH=maci64
as both the 32 and 64 bit versions are plausible targets on 64-bit machines.Compiling Octave support
Octave support is still experimental. Similarly to MATLAB, Octave requires compiling MEX files. This can be turned on by passing to make the path to the
mkoctfile
command:$ make MKOCTFILE=/path/to/mkoctfile Mac OS X troubleshooting
OS X 10.9 Mavericks, Xcode 5, clang, and GCC
Recent changes to Mac OS X toolkit that ships with Xcode have made compilation of VLFeat slightly more complex. Out of the box, Xcode 5.0 on Mac OS X Mavericks, for example, incorporates the clang compiler but not the GCC compiler. While VLFeat has been updated to use clang in this case, it is worth noting that this compiler does not yet support the OpenMP standard, meaning that multi-core computations would be disabled in this case.
Compiling OpenMP can be achieved by using the GCC compiler, for example obtaining it from MacPorts. However, anything more recent that GCC 4.2 will use the MacPorts runtime (C and C++). Since MATLAB links to the OS X native C and C++ runtime, this breaks the compatibility of VLFeat MEX files with MATLAB. In particular, while VLFeat does not use C++, MEX files do as the MEX API is coded in C++ internally (in particular MEX files are coded with the
-fexception
option as MEX API calls can throw exceptions, even though they look like regular C functions). In short, mixing C++ runtimes will cause MATLAB MEX files to crash every time an error is generated.The easiest solution at present is to use the
gcc-apple-4.2
from MacPorts. Unfortunately, this version does not support AVX instructions, but supports OpenMP and creates binaries that are MATLAB compatible.# Compile VLFeat in a manner compatible with MATLAB and OpenMP support $ sudo port install apple-gcc42 # Install MacPort's distribution of apple-gcc-42 $ make CC=/opt/local/bin/gcc-apple-42 # compile VLFeat using MacPort's GCC OS X 10.6 Snow Leopard, 64-bit, and MATLAB 2009b.
MATLAB 2009b for Snow Leopard has added 64 bit mex support and a corresponding extension
mexmaci64
. VLFeat now supports compiling for this platform, but the architecture must be specified manually when compiling, either like:$ make ARCH=maci64 or
$ make ARCH=maci Unfortunately, MATLAB 2009b's
mex
script has a bug that must be manually fixed in order for this procedure to work correctly. It is recommend to make backup of themex
script before attempting this. Th fix the bug, edit theMATLABROOT/bin/mex
script by cutting the line:get_arch # Call $MATLAB/bin/util/arch.sh and pasting it after the processing of options:
... shift done #PASTE get_arch call here get_arch # Call $MATLAB/bin/util/arch.sh if [ $v7_compat -eq 1 ] ; then fc_flags="$fc_flags -DMX_COMPAT_32" ... For Windows, the library bundles an NMake makefile (
Makefile.mak
). In order to use it, you must edit Makefile.mak to adjust the values of a number of configuration variables to match your setup. Once you have done that, start the Visual Studio Command Prompt and type$ nmake /f Makefile.mak # for the Windows 64 target $ nmake /f Makefile.mak ARCH=win32 # for the Windows 32 target For Windows platform, it is also possible to compile just the MATLAB MEX files from within MATLAB (using the
vl_compile
command). This is meant to help less experienced users that may need to recompile the mex file due to binary incompatibilities with older MATLAB versions.Windows troubleshooting
- syntax error: '=' unexpected:
Use
nmake /f Makefile.mak
. Without/f
, nmake will default to the wrong makefile.- 'long' followed by 'long' is illegal:
This error is usually caused by attempting to compile outside of the Visual Studio Command Prompt.
%tableofcontents; vlfeat/docsrc/tutorials/kdtree.html 0000644 0001750 0001750 00000013625 12570775230 016433 0 ustar dima dimaVLFeat includes a basic implementation of k-means clustering and hierarchical k-means clustering. They are designed to be lightweight in order to work on large datasets. In particular, they assume that the data are vectors of unsigned chars (one byte). While this is limiting for some application, it works well for clustering image descriptors, where very high precision is usually unnecessary. For more details, see the Integer k-means API reference.
Usage
Integer k-means (IKM) is run by the command
vl_ikmeans
. In order to demonstrate the usage of this command, we sample 1000 random points in the[0,255]^2
integer square and usevl_ikmeans
to get k=3 clusters:K = 3 ; data = uint8(rand(2,1000) * 255) ; [C,A] = vl_ikmeans(data,K) ; The program returns both the cluster centers
C
and the data-to-cluster assignmentsA
. By means of the cluster centersC
we can project more data on the same clustersdatat = uint8(rand(2,10000) * 255) ; AT = vl_ikmeanspush(datat,C) ; In order to visualize the results, we associate to each cluster a color and we plot the points:
cl = get(gca,'ColorOrder') ; ncl = size(cl,1) ; for k=1:K sel = find(A == k) ; selt = find(AT == k) ; plot(data(1,sel), data(2,sel), '.',... 'Color',cl(mod(k,ncl)+1,:)) ; hold on ; plot(datat(1,selt),datat(2,selt),'+',... 'Color',cl(mod(k,ncl)+1,:)) ; end Integer k-means. We show clusters of 2-D points obtained by integer k-means. There arek=3
clusters represented with different colors. The clusters have been estimated from 1000 points (displayed as dots). Then 10000 different points have been projected on the same clusters (displayed as crosses). The three big markers represent the cluster centers.Elkan
VLFeat supports two different implementations of k-means. While they produce identical output, the Elkan method requires fewer distance computations. The
method
parameters controls which method is used. Consider the case whenK=100
and our data is now 128 dimensional (e.g. SIFT descriptors):K=100; data = uint8(rand(128,10000) * 255); tic; [C,A] = vl_ikmeans(data,K,'method', 'lloyd') ; % default t_lloyd = toc tic; [C,A] = vl_ikmeans(data,K,'method', 'elkan') ; t_elkan = toc t_lloyd = 10.2884 t_elkan = 5.1405 %tableofcontents; vlfeat/docsrc/tutorials/covdet.html 0000644 0001750 0001750 00000033140 12570775230 016433 0 ustar dima dimaVLFeat implements the randomized kd-tree forest from FLANN. This enables fast medium and large scale nearest neighbor queries among high dimensional data points (such as those produced by SIFT).
Introduction
A kd-tree is a data structure used to quickly solve nearest-neighbor queries. Consider a set of 2D points uniformly distributed in the unit square:
X = rand(2, 100) ; A kd-tree is generated by using the
vl_kdtreebuild
function:kdtree = vl_kdtreebuild(X) ; The returned
kdtree
indexes the set of pointsX
. Given a query pointQ
, the functionvl_kdtreequery
returns its nearest neighbor inX
:Q = rand(2, 1) ; [index, distance] = vl_kdtreequery(kdforest, X, Q) ; Here
index
stores the index of the column ofX
that is closest to the pointQ
.distance
is the squared euclidean distance betweenX(index),Q
.A kd-tree is a hierarchal structure built by partitioning the data recursively along the dimension of maximum variance. At each iteration the variance of each column is computed and the data is split into two parts on the column with maximum variance. The splitting threshold can be selected to be the mean or the median (use the
ThresholdMethod
option ofvl_kdtreebuild
).![]()
kd-tree partitions of a uniform set of data points, using the mean (left image) and the median (right image) thresholding options ofvl_kdtreebuild
. On the bottom right corner a query point is marked along with the ten closest neighbors as found byvl_kdtreequery
. Figure generated byvl_demo_kdtree
.Querying
vl_kdtreequery
uses a best-bin first search heuristic. This is a branch-and-bound technique that maintains an estimate of the smallest distance from the query point to any of the data points down all of the open paths.
vl_kdtreequery
supports two important operations: approximate nearest-neighbor search and k-nearest neighbor search. The latter can be used to return the k nearest neighbors to a given query pointQ
. For instance:[index, distance] = vl_kdtreequery(kdtree, X, Q, 'NumNeighbors', 10) ; returns the closest 10 neighbors to
Q
inX
and their distances, stored along the columns ofindex
anddistance
.The
MaxComparisons
option is used to run an ANN query. The parameter specifies how many paths in the best-bin-first search of the kd-tree can be checked before giving up and returning the closest point encountered so far. For instance:[index, distance] = vl_kdtreequery(kdtree, X, Q, 'NumNeighbors', 10, 'MaxComparisons', 15) ; does not compare any point in
Q
with more than 15 points inX
.![]()
![]()
![]()
Finding the 10 approximated nearest neighbors for increasing values of theMaxComparisons
parameter. Note that at mostMaxComparisons
neighbors can be returned (if more are requested, they are ignored). Figure generated byvl_demo_kdtree_ann
.Randomized kd-tree forests
VLFeat supports constructing randomized forests of kd-trees to improve the effectiveness of the representation in high dimensions. The parameter
NumTrees
ofvl_kdtreebuild
specifies how many trees to use in constructing the forest. Each tree is constructed independently. Instead of always splitting on the maximally variant dimension, each tree chooses randomly among the top five most variant dimensions at each level. When querying,vl_kdtreequery
runs best-bin-first across all the trees in parallel. For instancekdtree = vl_kdtreebuild(X, 'NumTrees', 4) ; [index, distance] = vl_kdtreequery(kdtree, X, Q) ; constructs four trees and queries them.
![]()
![]()
![]()
The parameterNumTrees
tellsvl_kdtreebuild
to construct a number of randomized kd-trees. Figure generated byvl_demo_kdtree_forest
.%tableofcontents; vlfeat/docsrc/tutorials/kmeans.html 0000644 0001750 0001750 00000012235 12570775230 016427 0 ustar dima dimaThis tutorial introduces the
vl_covdet
VLFeat command implementing a number of co-variant feature detectors and corresponding descriptors. This family of detectors include SIFT as well as multi-scale conern (Harris-Laplace), and blob (Hessian-Laplace and Hessian-Hessian) detectors.Extracting frames and descriptors
The first example shows how to use
vl_covdet
to compute and visualize co-variant features. Fist, let us load an example image and visualize it:im = vl_impattern('roofs1') ; figure(1) ; clf ; image(im) ; axis image off ;
An example input image.The image must be converted to gray=scale and single precision. Then
vl_covdet
can be called in order to extract features (by default this uses the DoG cornerness measure, similarly to SIFT).imgs = im2single(rgb2gray(im)) ; frames = vl_covdet(imgs, 'verbose') ; The
verbose
option is not necessary, but it produces some useful information:vl_covdet: doubling image: yes vl_covdet: detector: DoG vl_covdet: peak threshold: 0.01, edge threshold: 10 vl_covdet: detected 3518 features vl_covdet: kept 3413 inside the boundary margin (2) The
vl_plotframe
command can then be used to plot these featureshold on ; vl_plotframe(frames) ; which results in the image
The default features detected byvl_covdet
use the DoG cornerness measure (like SIFT).In addition to the DoG detector,
vl_covdet
supports a number of other ones:
- The Difference of Gaussian operator (also known as trace of the Hessian operator or Laplacian operator) uses the local extrema trace of the multiscale Laplacian operator to detect features in scale and space (as in SIFT).
- The Hessian operator uses the local extrema of the mutli-scale determinant of Hessian operator.
- The Hessian Laplace detector uses the extrema of the multiscale determinant of Hessian operator for localisation in space, and the extrema of the multiscale Laplacian operator for localisation in scale.
- Harris Laplace uses the multiscale Harris cornerness measure instead of the determinant of the Hessian for localization in space, and is otherwise identical to the previous detector..
- Hessian Multiscale detects features spatially at multiple scales by using the multiscale determinant of Hessian operator, but does not attempt to estimate their scale.
- Harris Multiscale is like the previous one, but uses the multiscale Harris measure instead.
For example, to use the Hessian-Laplace operator instead of DoG, use the code:
frames = vl_covdet(imgs, 'method', 'HarrisLaplace') ; The following figure shows example of the output of these detectors:
Different detectors can produce a fairly different set of features.Understanding feature frames
To understand the rest of the tutorial, it is important to understand the geometric meaning of a feature frame. Features computed by
vl_covdet
are oriented ellipses and are defined by a translation $T$ and linear map $A$ (a $2\times 2$) which can be extracted as follows:T = frame(1:2) ; A = reshape(frame(3:6),2,2)) ; The map $(A,T)$ moves pixels from the feature frame (also called normalised patch domain) to the image frame. The feature is represented as a circle of unit radius centered at the origin in the feature reference frame, and this is transformed into an image ellipse by $(A,T)$.
In term of extent, the normalised patch domain is a square box centered at the origin, whereas the image domain uses the standard MATLAB convention and starts at (1,1). The Y axis points downward and the X axis to the right. These notions are important in the computation of normalised patches and descriptors (see later).
Affine adaptation
Affine adaptation is the process of estimating the &ldqo;affine shape&rdqo; of an image region in order to construct an affinely co-variant feature frame. This is useful in order to compensate for deformations of the image like slant, arising for example for small perspective distortion.
To switch on affine adaptation, use the
EstimateAffineShape
option:frames = vl_covdet(imgs, 'EstimateAffineShape', true) ; which detects the following features:
Affinely adapted features.Feature orientation
The detection methods discussed so far are rotationally invariant. This means that they detect the same circular or elliptical regions regardless of an image rotation, but they do not allow to fix and normalise rotation in the feature frame. Instead, features are estimated to be upright by default (formally, this means that the affine transformation $(A,T)$ maps the vertical axis $(0,1)$ to itself).
Estimating and removing the effect of rotation from a feature frame is needed in order to compute rotationally invariant descriptors. This can be obtained by specifying the
EstimateOrientation
option:frames = vl_covdet(imgs, 'EstimateOrientation', true, 'verbose') ; which results in the following features being detected:
Features with orientation detection.The method used is the same as the one proposed by D. Lowe: the orientation is given by the dominant gradient direction. Intuitively, this means that, in the normalized frame, brighter stuff should appear on the right, or that there should be a left-to-right dark-to-bright pattern.
In practice, this method may result in an ambiguous detection of the orientations; in this case, up to four different orientations may be assigned to the same frame, resulting in a multiplication of them.
Computing descriptors
vl_covdet
can also compute descriptors. Three are supported so far: SIFT, LIOP and raw patches (from which any other descriptor can be computed). To use this functionality simply add an output argument:[frames, descrs] = vl_covdet(imgs) ; This will compute SIFT descriptors for all the features. Each column of
descrs
is a 128-dimensional descriptor vector in single precision. Alternatively, to compute patches use:[frames, descrs] = vl_covdet(imgs, 'descriptor', 'liop') ; Using default settings, each column will be a 144-dimensional descriptor vector in single precision. If you wish to change the settings, use arguments described in LIOP tutorial
[frames, descrs] = vl_covdet(imgs, 'descriptor', 'patch') ; In this case each column of
descrs
is a stacked patch. To visualize the first 100 patches, one can use for example:w = sqrt(size(patches,1)) ; vl_imarraysc(reshape(patches(:,1:10*10), w,w,[])) ; ![]()
Patches extracted with the standard detectors (left) and adding affine adaptation (right).There are several parameters affecting the patches associated to features. First,
PatchRelativeExtent
can be used to control how large a patch is relative to the feature scale. The extent is half of the side of the patch domain, a square in the frame reference frame. Since most detectors latch on image structures (e.g. blobs) that, in the normalised frame reference, have a size comparable to a circle of radius one, settingPatchRelativeExtent
to 6 makes the patch about six times largerer than the size of the corner structure. This is approximately the default extent of SIFT feature descriptors.A second important parameter is
PatchRelativeSigma
which expresses the amount of smoothing applied to the image in the normalised patch frame. By default this is set to 1.0, but can be reduced to get &ldqo;sharper&rdqo; patches. Of course, the amount of smoothing is bounded below by the resolution of the input image: a smoothing of, say, less than half a pixel cannot be recovered due to the limited sampling rate of the latter. Moreover, the patch must be sampled finely enough to avoid aliasing (see next).The last parameter is
PatchResolution
. If this is equal to $w$, then the patch has a side of $2w+1$ pixels. (hence the sampling step in the normalised frame is given byPatchRelativeExtent
/PatchResolution
). Extracting higher resolution patches may be needed for larger extent and smaller smoothing. A good setting for this parameter may bePatchRelativeExtent
/PatchRelativeSigma
.Custom frames
Finally, it is possible to use
vl_covdet
to compute descriptors on custom feature frames, or to apply affine adaptation and/or orientation estimation to these.For example
delta = 30 ; xr = delta:delta:size(im,2)-delta+1 ; yr = delta:delta:size(im,1)-delta+1 ; [x,y] = meshgrid(xr,yr) ; frames = [x(:)'; y(:)'] ; frames(end+1,:) = delta/2 ; [frames, patches] = vl_covdet(imgs, ... 'frames', frames, ... 'estimateAffineShape', true, ... 'estimateOrientation', true) ; computes affinely adapted and oriented features on a grid:
Custom frame (on a grid) after affine adaptation.Getting the scale spaces
vl_covdet
can return additional information about the features, including the scale spaces and scores for each detected feature. To do so use the syntax:[frames, descrs, info] = vl_covdet(imgs) ; This will return a structure info
info = gss: [1x1 struct] css: [1x1 struct] peakScores: [1x351 single] edgeScores: [1x351 single] orientationScore: [1x351 single] laplacianScaleScore: [1x351 single] The last four fields are the peak, edge, orientation, and Laplacian scale scores of the detected features. The first two were discussed before, and the last two are the scores associated to a specific orientation during orientation assignment and to a specific scale during Laplacian scale estimation.
The first two fields are the Gaussian scale space and the cornerness measure scale space, which can be plotted by means of
vl_plotss
. The following is the of the Gaussian scale space for our example image:
Gaussian scale space.The following is an example of the corresponding cornerness measure:
Cornerness scale space (Difference of Gaussians).%tableofcontents; vlfeat/docsrc/tutorials/utils.html 0000644 0001750 0001750 00000004057 12570775230 016314 0 ustar dima dimaThis tutorial shows how to use the K-means algorithm using the VlFeat implementation of Llloyd's algorithm as well as other faster variants.
Running K-means
KMeans is a clustering algorithm. Its purpose is to partition a set of vectors into $K$ groups that cluster around common mean vector. This can also be thought as approximating the input each of the input vector with one of the means, so the clustering process finds, in principle, the best dictionary or codebook to vector quantize the data.
Consider a dataset containing 1000 randomly sampled 2D points:
numData = 5000 ; dimension = 2 ; data = rand(dimension,numData) ; The function
vl_kmeans
can be used to cluster the data into, say, 30 groups:numClusters = 30 ; [centers, assignments] = vl_kmeans(data, numClusters); By default, this uses the the Lloyd algorithm, a method that alternates between optimizing the cluster centers and the data-to-center assignments. Once this process terminates, the matrix
centers
contains the cluster centers and the vectorassignments
the (hard) assignments of the input data to the clusters. The cluster centers are also called means because it can be shown that, when the clustering is optimal, the centers are the means of the corresponding data points. The cluster centers and assignments can be visualized as follows: KMeans clustering of 5000 randomly sampled data points. The black dots are the cluster centers.Given a new data point
x
, this can be mapped to one of the clusters by looking for the closest center:x = rand(dimension, 1) ; [~, k] = min(vl_alldist(x, centers)) ; For larger datastes, this process may be significantly accelerated by using KDTrees or other approximate nearest neighbor procedures.
Choosing an initialization method
K-means uses local optimization algorithms and is therefore sensitive to initalization. By default,
vl_kmeans
initializes the cluster centers by picks $K$ data points at random. Other initalization strategies can be selected as well. kmeans++ is a popular method that greedily pick $K$ data points that are maximally different, and can be use as follows:[centers, assignments] = vl_kmeans(data, numClusters, 'Initialization', 'plusplus') ; Choosing an optimization algorithm
In addition to the original KMeans algorithm proposed by Lloyd,
vl_kmeans
supports two additional algorithms: Elkan's variant, an exact algorithm using an acceleration technique based the triangular inequality, and ANN, an approximated algorithm using approximate nearest neighbours.These optimization methods can be enabled by setting the
'Algorithm'
parameter to'Lloyd'
,'Elkan'
or'ANN'
respectively. When using the'ANN'
algorithm, the user can also specify the parameters'MaxNumComparisons'
and'NumTrees'
to configure the KD-tree used used as ANN. In particular,'MaxNumComparisons'
controls the trade-off between approximation quality and speed.
vl_demo_kmeans_ann_speed
compares the speed of the three algorithms. Because of the random initialization, each of the KMeans calls converges to a different local minimum in a different amount of iterations. In order to measure more accurately the speed of each pass, a relatively small number of'MaxNumIterations'
option) is selected. Note that the speedup factor are in general much more dramatic when truly large datasets are considered. Comparisons of Elkan, Lloyd and ANN for different values ofMaxNumComparison
, expressed as a fraction of the number of clusters. The figure reports the duration, final energy value, and speedup factor, using both the serial and parallel versions of the code. The figure was generated usingvl_demo_kmeans_ann_speed
.vlfeat/docsrc/tutorials/aib.html 0000644 0001750 0001750 00000003702 12570775230 015703 0 ustar dima dima This is a list of other notable MATLAB functions included in VLFeat
vl_imsmooth
smoothes an image by a Gaussian kernel (simple but very useful as it is generally much faster than MATLAB's general purpose smoothing functions).vl_plotframe
plots a variety of feature frame types (such as oriented ellipses).vl_binsum
performs binned summations, useful as a building block for the fast computation of histograms.vl_whistc
computes weighed histograms.vl_imarray
andvl_imarraysc
arrange and visualize multiple images in a gridvl_imsc
scales the image range;vl_tightsubplot
is similar to built-insubplot
, but produces narrower margins.vl_cf
makes a copy of a figure.vl_rodr
andvl_irodr
compute the Rodrigues' formula and its inversevl_override
overrides members of a structure with members of another structure.vl_imwbackward
warps an image by the inverse mapping method (generally much faster than MATLAB general purpose warping functions).vl_waffine
computes the affine warp of a set of points.vl_tps
,vl_tpsu
,vl_wtps
compute the thin-plate spline warp of a set of points.vl_witps
computes the inverse thin plate warp of a set of point (by numerically inverting the transformation). They may be used in combination withvl_imwbackward
.vl_xyz2lab
,vl_xyz2luv
,vl_xyz2rgb
,vl_rgb2xyz
convert color spaces.vl_rcos
,vl_gaussian
,vl_dgaussian
,vl_ddgaussian
compute some useful special functions.vlfeat/docsrc/tutorials/mser.html 0000644 0001750 0001750 00000021066 12570775230 016121 0 ustar dima dima The Agglomerative Information Bottleneck (AIB) algorithm greedily compresses discrete data by iteratively merging the two elements which cause the mutual information between the data and the class labels to decreases as little as possible.
Here we test AIB on the problem of finding a discriminatively optimal quantization of a mixture of Gaussians. The data in this case is 2 dimensional:
Random data generated from a Gaussian mixture with three components (class labels are indicated by color).We quantize this data on a fixed lattice (a 20x20 grid shown in the figures below), and construct histograms for each class.
f1 = quantize(X1,D,K) ; f2 = quantize(X2,D,K) ; f3 = quantize(X3,D,K) ; Pcx(1,:) = vl_binsum(Pcx(1,:), ones(size(f1)), f1) ; Pcx(2,:) = vl_binsum(Pcx(2,:), ones(size(f2)), f2) ; Pcx(3,:) = vl_binsum(Pcx(3,:), ones(size(f3)), f3) ; Next we apply AIB:
[parents, cost] = vl_aib(Pcx) ; This provides us with a list of parents of each column in
Pcx
, forming a tree of merges. We can now "cut" this tree to obtain any number of clusters. Three "cuts" of the merge tree, showing 10, 3, and 2 clusters. The gray squares are nodes of the tree which did not have any data points which were quantized to them.Notice that the resulting clusters do not have to be contiguous in the original space.
%tableofcontents; vlfeat/docsrc/tutorials/encode.html 0000644 0001750 0001750 00000010575 12570775755 016427 0 ustar dima dimaMaximally Stable Extremal Regions (MSER) is a feature detector; Like the SIFT detector, the MSER algorithm extracts from an image
I
a number of co-variant regions, called MSERs. An MSER is a stable connected component of some level sets of the imageI
. Optionally, elliptical frames are attached to the MSERs by fitting ellipses to the regions. For a more in-depth explanation of the MSER detector, see our API reference for MSERExtracting MSERs
Each MSERs can be identified uniquely by (at least) one of its pixels
x
, as the connected component of the level set at levelI(x)
which containsx
. Such a pixel is called seed of the region.To demonstrate the usage of the MATLAB command
vl_mser
we open MATLAB and load a test imagepfx = fullfile(vl_root,'data','spots.jpg') ; I = imread(pfx) ; image(I) ; A test image.We then convert the image to a format that is suitable for the
vl_mser
command.I = uint8(rgb2gray(I)) ; We compute the region seeds and the elliptical frames by
[r,f] = vl_mser(I,'MinDiversity',0.7,... 'MaxVariation',0.2,... 'Delta',10) ; We plot the region frames by
f = vl_ertr(f) ; vl_plotframe(f) ;
vl_ertr
transposes the elliptical frame and is required here because thevl_mser
code assumes that the row index is the first index, but the normal image convention assumes that this is thex
(column) index.Plotting the MSERs themselves is a bit more involved as they have arbitrary shape. To this end, we exploit two functions:
vl_erfill
, which, given an image and a region seed, returns a list of the pixels belonging to that region, and the MATLAB built-incontour
, which draws the contour lines of a function. We start byM = zeros(size(I)) ; for x=r' s = vl_erfill(I,x) ; M(s) = M(s) + 1; end which computes a matrix
M
whose value are equal to the number of overlapping extremal regions. Next, we useM
andcontour
to display the region boundaries:figure(2) ; clf ; imagesc(I) ; hold on ; axis equal off; colormap gray ; [c,h]=contour(M,(0:max(M(:)))+.5) ; set(h,'color','y','linewidth',3) ; Extracted MSERs (left) and fitted ellipses (right).MSER parameters
In the original formulation, MSERs are controlled by a single parameter
Δ
, which controls how the stability is calculated. Its effect is shown in the figure below. Effect ofΔ
. We start with a synthetic image which has an intensity profile as shown. The bumps have heights equal to 32, 64, 96, 128 and 160. As we increaseΔ
, fewer and fewer regions are detected until finally atΔ=160
there is no regionR
which is stable atR(+Δ)
.The stability of an extremal region
R
is the inverse of the relative area variation of the regionR
when the intensity level is increased byΔ
. Formally, the variation is defined as:|R(+Δ) - R| ----------- |R| where
|R|
denotes the area of the extremal regionR
,R(+Δ)
is the extremal region+Δ
levels up which containsR
and|R(+Δ) - R|
is the area difference of the two regions.A stable region has a small variation. The algorithm finds regions which are "maximally stable", meaning that they have a lower variation than the regions one level below or above. Note that due to the discrete nature of the image, the region below / above may be coincident with the actual region, in which case the region is still deemed maximal.
However, even if an extremal region is maximally stable, it might be rejected if:
- it is too big (see the parameter
MaxArea
);- it is too small (see the parameter
MinArea
);- it is too unstable (see the parameter
MaxVariation
);- it is too similar to its parent MSER (see the parameter
MinDiversity
).By default, MSERs are extracted for both dark-on-bright regions and bright-on-dark regions. To control this, parmeters
BrightOnDark
andDarkOnBright
which take values 0 or 1 to enable or disable the regions. For example:[r,f] = vl_mser(I,'MinDiversity',0.7,... 'MaxVariation',0.2,... 'Delta',10,... 'BrightOnDark',1,'DarkOnBright',0) ; computes the regions in green in the figure below.
Extracted MSERs (left) and fitted ellipses (right) for both bright-on-dark (green) and dark-on-bright (yellow).Conventions
As mentioned in the introduction,
vl_mser
uses matrix indices as image coordinates. Compared to the usual MATLAB convention for images, this means that thex
andy
axis are swapped (this has been done to make the convention consistent with images with three or more dimensions). Thus the frames computed by the program may need to be "transposed" as in:[r,f] = vl_mser(I) ; f = vl_ertr(f) ; On the other hand, the region seeds
r
are already in row major format, which is the standard MATLAB format for pixel indices.Instead of transposing the frames, one can start by transposing the image. In this case, the frames
f
have the standard image convention, but the region seeds are in column-major format and may need to be "transposed" as in:[r,f] = vl_mser(I') ; [i,j] = sub2ind(size(I'),r) ; r = ind2sub(size(I),j,i) ; The command line utility
mser
uses the normal image convention (because images are rasterized in column-major order). Therefore the image frames are in the standard format, and the region seeds are in column major format.In order to convert from the command line utility convention to the MATLAB convention one needs also to recall that MATLAB coordinates starts from (1,1), but the command line utility uses the more common convention (0,0). For instance, let the files
image.frame
andimage.seed
contain the feature frames and seeds in ASCII format as generated by the command line utility. Thenr_ = load('image.seed')' + 1 ; f_ = load('image.frame')' ; f_(1:2,:) = f_(1:2,:) + 1 ; [r,f] = vl_mser(I') ; % notice the transpose produces identical (up to numerical noise) region seeds
r
andr_
and framesf
andf_
.%tableofcontents; vlfeat/docsrc/tutorials/svm.html 0000644 0001750 0001750 00000012652 12570775230 015761 0 ustar dima dimaThis short tutorial shows how to compute Fisher vector and VLAD encodings with VLFeat MATLAB interface.
These encoding serve a similar purposes: summarizing in a vectorial statistic a number of local feature descriptors (e.g. SIFT). Similarly to bag of visual words, they assign local descriptor to elements in a visual dictionary, obtained with vector quantization (KMeans) in the case of VLAD or a Gaussian Mixture Models for Fisher Vectors. However, rather than storing visual word occurrences only, these representations store a statistics of the difference between dictionary elements and pooled local features.
Fisher encoding
The Fisher encoding uses GMM to construct a visual word dictionary. To exemplify constructing a GMM, consider a number of 2 dimensional data points (see also the GMM tutorial). In practice, these points would be a collection of SIFT or other local image features. The following code fits a GMM to the points:
numFeatures = 5000 ; dimension = 2 ; data = rand(dimension,numFeatures) ; numClusters = 30 ; [means, covariances, priors] = vl_gmm(data, numClusters); Next, we create another random set of vectors, which should be encoded using the Fisher Vector representation and the GMM just obtained:
numDataToBeEncoded = 1000; dataToBeEncoded = rand(dimension,numDataToBeEncoded); The Fisher vector encoding
enc
of these vectors is obtained by calling thevl_fisher
function using the output of thevl_gmm
function:encoding = vl_fisher(datatoBeEncoded, means, covariances, priors); The
encoding
vector is the Fisher vector representation of the datadataToBeEncoded
.Note that Fisher Vectors support several normalization options that can affect substantially the performance of the representation.
VLAD encoding
The Vector of Linearly Agregated Descriptors is similar to Fisher vectors but (i) it does not store second-order information about the features and (ii) it typically use KMeans instead of GMMs to generate the feature vocabulary (although the latter is also an option).
Consider the same 2D data matrix
data
used in the previous section to train the Fisher vector representation. To compute VLAD, we first need to obtain a visual word dictionary. This time, we use K-means:numClusters = 30 ; centers = vl_kmeans(dataLearn, numClusters); Now consider the data
dataToBeEncoded
and use thevl_vlad
function to compute the encoding. Differently fromvl_fisher
,vl_vlad
requires the data-to-cluster assignments to be passed in. This allows using a fast vector quantization technique (e.g. kd-tree) as well as switching from soft to hard assignment.In this example, we use a kd-tree for quantization:
kdtree = vl_kdtreebuild(centers) ; nn = vl_kdtreequery(kdtree, centers, dataEncode) ; Now we have in the
nn
the indexes of the nearest center to each vector in the matrixdataToBeEncoded
. The next step is to create an assignment matrix:assignments = zeros(numClusters,numDataToBeEncoded); assignments(sub2ind(size(assignments), nn, 1:length(nn))) = 1; It is now possible to encode the data using the
vl_vlad
function:enc = vl_vlad(dataToBeEncoded,centers,assignments); Note that, similarly to Fisher vectors, VLAD supports several normalization options that can affect substantially the performance of the representation.
%tableofcontents; vlfeat/docsrc/tutorials/plots-rank.html 0000644 0001750 0001750 00000021756 12570775230 017253 0 ustar dima dimaVLFeat includes fast SVM solvers, SGC [1] and (S)DCA [2], both implemented in
vl_svmtrain
. The function also implements features, like Homogeneous kernel map expansion and SVM online statistics. (S)DCA can also be used with different loss functions.Support vector machine
A simple example on how to use
vl_svmtrain
is presented below. Let's first load and plot the training data:% Load training data X and their labels y vl_setup demo % to load the demo data load('vl_demo_svm_data.mat'); Xp = X(:,y==1); Xn = X(:,y==-1); figure plot(Xn(1,:),Xn(2,:),'*r') hold on plot(Xp(1,:),Xp(2,:),'*b') axis equal ; Now we have a plot of the tutorial training data:
Training Data.Now we will set the learning parameters:
lambda = 0.01 ; % Regularization parameter maxIter = 1000 ; % Maximum number of iterations Learning a linear classifier can be easily done with the following 1 line of code:
[w b info] = vl_svmtrain(X, y, lambda, 'MaxNumIterations', maxIter) Now we can plot the output model over the training data.
% Visualisation eq = [num2str(w(1)) '*x+' num2str(w(2)) '*y+' num2str(b)]; line = ezplot(eq, [-0.9 0.9 -0.9 0.9]); set(line, 'Color', [0 0.8 0],'linewidth', 2); The result is plotted in the following figure.
Learned model.The output
info
is a struct containing some statistic on the learned SVM:info = solver: 'sdca' lambda: 0.0100 biasMultiplier: 1 bias: 0.0657 objective: 0.2105 regularizer: 0.0726 loss: 0.1379 dualObjective: 0.2016 dualLoss: 0.2742 dualityGap: 0.0088 iteration: 525 epoch: 3 elapsedTime: 0.0300 It is also possible to use under some assumptions [3] a homogeneous kernel map expanded online inside the solver. This can be done with the following commands:
% create a structure with kernel map parameters hom.kernel = 'KChi2'; hom.order = 2; % create the dataset structure dataset = vl_svmdataset(X, 'homkermap', hom); % learn the SVM with online kernel map expansion using the dataset structure [w b info] = vl_svmtrain(dataset, y, lambda, 'MaxNumIterations', maxIter) The above code creates a training set without applying any homogeneous kernel map to the data. When the solver is called it will expand each data point with a Chi Squared kernel of period 2.
Diagnostics
VLFeat allows to get statistics during the training process. It is sufficient to pass a function handle to the solver. The function will be then called every
DiagnosticFrequency
time.(S)DCA diagnostics also provides the duality gap value (the difference between primal and dual energy), which is the upper bound of the primal task sub-optimality.
% Diagnostic function function diagnostics(svm) energy = [energy [svm.objective ; svm.dualObjective ; svm.dualityGap ] ] ; end % Training the SVM energy = [] ; [w b info] = vl_svmtrain(X, y, lambda,... 'MaxNumIterations',maxIter,... 'DiagnosticFunction',@diagnostics,... 'DiagnosticFrequency',1) The objective values for the past iterations are kept in the matrix
energy
. Now we can plot the objective values from the learning process.figure hold on plot(energy(1,:),'--b') ; plot(energy(2,:),'-.g') ; plot(energy(3,:),'r') ; legend('Primal objective','Dual objective','Duality gap') xlabel('Diagnostics iteration') ylabel('Energy')
SVM objective values plot.References
- [1] Y. Singer and N. Srebro. Pegasos: Primal estimated sub-gradient solver for SVM. In Proc. ICML, 2007.
- [2] S. Shalev-Schwartz and T. Zhang. Stochastic Dual Coordinate Ascent Methods for Regularized Loss Minimization. 2013.
- [3] A. Vedaldi and A. Zisserman. Efficient additive kernels via explicit feature maps. In PAMI, 2011.
vlfeat/docsrc/tutorials/hikm.html 0000644 0001750 0001750 00000007325 12570775230 016105 0 ustar dima dima This tutorial illustrates the use of the functions
vl_roc
,vl_det
, andvl_pr
to generate ROC, DET, and precision-recall curves.VLFeat includes support for plotting starndard information retrieval curves such as the Receiver Operating Characteristic (ROC) and the Precision-Recall (PR) curves.
Consider a set of samples with labels
labels
and scorescores
.scores
is typically the output of a classifier, with higher scores corresponding to positive labels. Ideally, sorting the data by decreasing scores should leave all the positive samples first and the negative samples last. In practice, a classifier is not perfect and the ranking is not ideal. The tools discussed in this tutorial allow to evaluate and visualize the quality of the ranking.For the sake of the illustration generate some data randomly as follows:
numPos = 20 ; numNeg = 100 ; labels = [ones(1, numPos) -ones(1,numNeg)] ; scores = randn(size(labels)) + labels ; In this case, there have five times more negative samples than positive ones. The scores are correlated to the labels as expected, but do not allow for a perfect separation of the two classes.
ROC and DET curves
To visualize the quality of the ranking, one can plot the ROC curve by using the
vl_roc
function:vl_roc(labels, scores) ; This produces the figure
An example ROC curve.The ROC curve is the parametric curve given by the true positve rate (TPR) against the true negative rate (TNR). These two quantities can be obtained from
vl_roc
as follows:[tpr, tnr] = vl_roc(labels, scores) ; The TPR value
tpr(k)
is the percentage of positive samples that have rank smaller or equal thank
(where ranks are assigned by decreasing scores).tnr(k)
is instead the percentage of negative samples that have rank larger thank
. Therefore, if one classifies the samples with rank smaller or equal thank
to be positive and the rest to be negative,tpr(k)
andtnr(k)
are repsectively the probability that a positive/negative sample is classified correctly.Moving from rank
k
to rankk+1
, if the sample of rankk+1
is positive thentpr
increases; otherwisetnr
decreases. An ideal classifier has all the positive samples first, and the corresponding ROC curve is one that describes two sides of the unit square.The Area Under the Curve (AUC) is an indicator of the overall quality of a ROC curve. For example, the ROC of the ideal classifier has AUC equal to 1. Another indicator is the Equal Error Rate (EER), the point on the ROC curve that corresponds to have an equal probability of miss-classifying a positive or negative sample. This point is obtained by intersecting the ROC curve with a diagonal of the unit square. Both AUC and EER can be computed by
vl_roc
:[tpr, tnr, info] = vl_roc(labels, scores) ; disp(info.auc) ; disp(info.eer) ;
vl_roc
has a couple of useful functionalities:
- Any sample with label equal to zero is effecitvely ignored in the evaluation.
- Samples with scores equal to
-inf
are assumed to be never retrieved by the classifier. For these, the TNR is conventionally set to be equal to zero.- Additional negative and positive samples with
-inf
score can be added to the evaluation by means of thenumNegatives
andnumPositives
options. For example,vl_roc(labels,scores,'numNegatives',1e4)
sets the number of negative samples to 10,000. This can be useful when evaluating large retrieval systems, for which one may want to record inlabels
andscores
only the top ranked results from a classifier.- Different variants of the ROC plot can be produced. For example
vl_roc(labels,scores,'plot','tptn')
swaps the two axis, plotting the TNR against the TPR. Since the TPR is also the recall (i.e., the percentage of positive samples retrieved up to a certain rank), this makes the plot more directly comparable to a precision-recall plot.
Variants of the ROC plot.A limitation of the ROC curves in evaluating a typical retrieval system is that they put equal emphasis on false positive and false negative errors. In a tipical retrieval application, however, the vast majority of the samples are negative, so the false negative rate is typically very small for any operating point of interest. Therefore the emphasis is usually on the very first portion of the rank, where the few positive samples should concentrate. This can be emphasized by using either precision-recall plot or a variant of the ROC curves called Detection Error Tradeoff (DET) curves.
A DET curve plots the FNR (also called false alarm rate) against teh FPR (also called miss rate) in logarithmic coordiantes. It can be generated by
vl_det
function call:
An example DET curve.Precision-recall curves
Both ROC and DET curves normalize out the relative proportions of positive and negative samples. By contrast, a Precision-Recall (PR) curve reflects this directly. One can plot the PR curve by using the
vl_pr
function:vl_pr(labels, scores) ; This produces the figure
An example precision-recall curve.The PR curve is the parametric curve given by precision and recall. These two quantities can be obtained from
vl_roc
as follows:[recall, precision] = vl_roc(labels, scores) ; The precision value
precision(k)
is the proportion of samples with rank smaller or equal thank-1
that are positive(where ranks are assigned by decreasing scores).recall(k)
is instead the percentage of positive samples that have rank smaller or equal thank-1
. For example, if the first two samples are one positive and one negative,precision(3)
is 1/2. If there are in total 5 positive samples, thenrecall(3)
is 1/5.Moving from rank
k
to rankk+1
, if the sample of rankk+1
is positive then bothprecision
andrecall
increase; otherwiseprecision
decreases andrecall
stays constant. This gives the PR curve a characteristic saw-shape. For aan ideal classifier that ranks all the positive samples first the PR curve is one that describes two sides of the unit square.Similar to the ROC curves, the Area Under the Curve (AUC) can be used to summarize the quality of a ranking in term of precision and recall. This can be obtained as
info.auc
by[rc, pr, info] = vl_pr(labels, scores) ; disp(info.auc) ; disp(info.ap) ; disp(info.ap_interp_11) ; The AUC is obtained by trapezoidal interpolation of the precision. An alternative and usually almost equivalent metric is the Average Precision (AP), returned as
info.ap
. This is the average of the precision obtained every time a new positive sample is recalled. It is the same as the AUC if precision is interpolated by constant segments and is the definition used by TREC most often. Finally, the 11 points interpolated average precision, returned asinfo.ap_interp_11
. This is an older TREC definition and is obtained by taking the average of eleven precision values, obtained as the maximum precision for recalls largerer than 0.0, 0.1, ..., 1.0. This particular metric was used, for example, in the PASCAL VOC challenge until the 2008 edition.%tableofcontents; vlfeat/docsrc/tutorials/slic.html 0000644 0001750 0001750 00000002702 12570775230 016101 0 ustar dima dimaVLFeat offers a hierarchical version of integer k-means, which recursively applies
vl_ikmeans
to compute finer and finer partitions. For more details see Hierarchical Integer k-means API reference and the Integer k-means tutorial.Usage
First, we generate some random data to cluster in
[0,255]^2
:data = uint8(rand(2,10000) * 255) ; datat = uint8(rand(2,100000)* 255) ; To cluster this data, we simply use
vl_hikmeans
:K = 3 ; nleaves = 100 ; [tree,A] = vl_hikmeans(data,K,nleaves) ; Here
nleaves
is the desired number of leaf clusters. The algorithm terminates when there are at leastnleaves
nodes, creating a tree withdepth = floor(log(K nleaves))
To assign labels to the new data, we use
vl_hikmeanspush
:AT = vl_hikmeanspush(tree,datat) ; Hierarchical integer K-means. Left: A depiction of the recursive clusters. Each node is a cluster center. The root note is not depicted (its center would be the mean of the dataset). Right: Clusters are represented as different colors (here are more than 100 clusters, but only three colors are used).Tree structure
The output
tree
is a MATLAB structure representing the tree of clusters:> tree tree = K: 3 depth: 5 centers: [2x3 int32] sub: [1x3 struct] The field
centers
is the matrix of the cluster centers at the root node. If the depth of the tree is larger than 1, then the fieldsub
is a structure array with one entry for each cluster. Each element is in turn a tree:> tree.sub ans = 1x3 struct array with fields: centers sub with a field
centers
for its clusters and a fieldsub
for its children. When there are no children, this field is equal to the empty matrix> tree.sub(1).sub(1).sub(1).sub(1) ans = centers: [2x3 int32] sub: [] Elkan
VLFeat supports two different implementations of k-means. While they produce identical output, the Elkan method is sometimes faster. The
method
parameters controls which method is used. Consider the case whenK=10
and our data is now 128 dimensional (e.g. SIFT descriptors):K=10; nleaves = 1000; data = uint8(rand(128,10000) * 255); tic; [tree,A] = vl_hikmeans(data,K,nleaves,'method', 'lloyd') ; % default t_lloyd = toc tic; [tree,A] = vl_hikmeans(data,K,nleaves,'method', 'elkan') ; t_elkan = toc t_lloyd = 8.0743 t_elkan = 3.0427 vlfeat/docsrc/tutorials/hog.html 0000644 0001750 0001750 00000013147 12570775230 015731 0 ustar dima dima SLIC is superpixel extraction (segmentation) method based on a local version of k-means. For a detailed description of the algorithm, see the SLIC API reference.
This demo shows how to use SLIC to extract superpixels from this image:
The image to be segmentedIn the simplest form, SLIC can be called as:
% im contains the input RGB image as a SINGLE array regionSize = 10 ; regularizer = 10 ; segments = vl_slic(im, regionSize, regularizer) ; By making varting
regionSize
andregularizer
one obtains the segmentations: SLIC segmentationsregionSize
spaning the values 10,30, andregularizer
the values 0.01, 0.1, 1.SLIC is often intended to be applied on top of LAB rather than RGB images. To do this, simpyl convert the image to LAB format before calling
vl_slic
.% IM contains the image in RGB format as before imlab = vl_xyz2lab(vl_rgb2xyz(im)) ; segments = vl_slic(imlab, 10, 0.1) ; %tableofcontents; vlfeat/docsrc/tutorials/frame.html 0000644 0001750 0001750 00000021011 12570775230 016233 0 ustar dima dimaThe HOG features are widely use for object detection. HOG decomposes an image into small squared cells, computes an histogram of oriented gradients in each cell, normalizes the result using a block-wise pattern, and return a descriptor for each cell.
Stacking the cells into a squared image region can be used as an image window descriptor for object detection, for example by means of an SVM.
This tutorial shows how to use the VLFeat function
vl_hog
to compute HOG features of various kind and manipulate them.Basic HOG computation
We start by considering an example input image:
An example image.HOG is computed by calling the
vl_hog
function:cellSize = 8 ; hog = vl_hog(im, cellSize, 'verbose') ; The same function can also be used to generate a pictorial rendition of the features, although this unavoidably destroys some of the information contained in the feature itself. To this end, use the
render
command:imhog = vl_hog('render', hog, 'verbose') ; clf ; imagesc(imhog) ; colormap gray ; This should produce the following image:
Standard HOG features with a cell size of eight pixels.HOG is an array of cells, with the third dimension spanning feature components:
> size(hog) ans = 16 16 31 In this case the feature has 31 dimensions. HOG exists in many variants. VLFeat supports two: the UoCTTI variant (used by default) and the original Dalal-Triggs variant (with 2×2 square HOG blocks for normalization). The main difference is that the UoCTTI variant computes bot directed and undirected gradients as well as a four dimensional texture-energy feature, but projects the result down to 31 dimensions. Dalal-Triggs works instead with undirected gradients only and does not do any compression, for a total of 36 dimension. The Dalal-Triggs variant can be computed as
% Dalal-Triggs variant cellSize = 8 ; hog = vl_hog(im, cellSize, 'verbose', 'variant', 'dalaltriggs') ; imhog = vl_hog('render', hog, 'verbose', 'variant', 'dalaltriggs') ; The result is visually very similar:
Dalal-Triggs variant. Differences with the standard version are difficult to appreciated in the rendition.Flipping HOG from left to right
Often it is necessary to flip HOG features from left to right (for example in order to model an axis symmetric object). This can be obtained analytically from the feature itself by permuting the histogram dimensions appropriately. The permutation is obtained as follows:
% Get permutation to flip a HOG cell from left to right perm = vl_hog('permutation') ; Then these two examples produce identical results (provided that the image contains an exact number of cells:
imHog = vl_hog('render', hog) ; imHogFromFlippedImage = vl_hog('render', hogFromFlippedImage) ; imFlippedHog = vl_hog('render', flippedHog) ; This is shown in the figure:
Flipping HOG features from left to right either by flipping the input image or the features directly.Other HOG parameters
vl_hog
supports other parameters as well. For example, one can specify the number of orientations in the histograms by thenumOrientations
option:% Specify the number of orientations hog = vl_hog(im, cellSize, 'verbose', 'numOrientations', o) ; imhog = vl_hog('render', hog, 'verbose', 'numOrientations', o) ; Changing the number of orientations changes the features quite significantly:
HOG features fornumOrientations
equal to 3, 4, 5, 9, and 21 repsectively.Another useful option is
BilinearOrientations
switching on the bilinear orientation assignment of the gradient (this is not used in certain implementation like UoCTTI).% Specify the number of orientations hog = vl_hog(im,cellSize,'numOrientations', 4) ; imhog = vl_hog('render', hog, 'numOrientations', 4) ; resulting in
From left to right: input image, hard orientation assigments fornumOrientations
equals to four, and soft orientation assigments.%tableofcontents; vlfeat/docsrc/tutorials/liop.html 0000644 0001750 0001750 00000003361 12570775230 016114 0 ustar dima dimaThis page introduces the notion of local feature frame used extensively in VLFeat. A feature frame or simply a frame, is a geometric object such as a point, a circle, or an ellipse representing the location and shape of an image feature. Frame types are closed under certain classes of transformations of the plane (for example circles are closed under similarity transformations) and can be used in corresponding co-variant feature detectors.
Types of frames
VLFeat uses five types of frames:
- points defined by their center $(x,y)$;
- circles defined by their center $(x,y)$ and radius $\sigma$;
- ellipses defined by their center $T = (x,y)$, and a positive semidefinte matrix $\Sigma$ such that the ellipse is the set of points $\{\bx \in \real^2: (\bx-T)^\top\Sigma^{-1}(\bx-T)=1\}$;
- oriented circles defined by their center $(x,y)$, their radius $\sigma$, and rotation $\theta$;
- and oriented ellipses defined by an affine transformation $(A,T)$, where $A\in\real^{2\times2}$ is the linear component and $T\in\real^2$ the translation.
A frame of each of these types can then be represented by 2, 3, 4, 5, or 6 numbers respectively, packed into a vector
frame
using the conventions detailed invl_plotframe
.Features frames as geometric frames
The purpose of a frame is twofold. First, it specifies a local image region. Second, and perhaps more importantly, it specifies an image transformation. A frame instance can in fact be thought as a transformed variant of a canonical or standard frame.
For example, a point $(x,y)$ can be seen as the translated version of the origin $(0,0)$ taken as canonical point frame. Likewise, a circle with center $(x,y)$ and radius $\sigma$ can be seen as the translated and rescaled version of a unit circle centered at the origin, taken as canonical circular frame.
In general, different classes of frames are closed under different classes of 2D transformations. For instance, points are closed under all transformations, while disks are closed under translations, rigid motions, similarity, but not general affine transformations. Within a class of compatible transformations, a frame may specify one uniquely if it can be obtained by transforming the standard frame in only one way. For instance, a point $(x,y)$ can be obtained from $(0,0)$ through a unique translation $T=(x,y)$. Likewise, a circle can be obtained from the standard circle by a unique translation and rescaling. However, neither a point or a circle is sufficient to fully specify a similarity transformation (e.g. a circle leaves the rotation undetermined).
Since frames specify transformations of the image domain, i.e. coordinate changes, they are surrogates of geometric reference frames. In particular, the mapping from a standard frame to one measured by a local feature detector is often undone to normalize the local image appearance, a key process in the computation of invariant feature descriptors.
Oriented frames
While unoriented frames (points, circles, and ellipses) are easy to understand, a few words should be spent illustrating their oriented variants. Intuitively, an oriented circle (ellipse) is a circle (ellipse) with a radius representing its orientation, such as the following:
The standard oriented frame: a unit circle, centered at the origin, with a radius pointing downwards. This frame can be seen as an oriented disc with null translation, unit radius, and null rotation, encoded as the 4D vector[0;0;1;0]
; alternatively, it can be seen as an oriented ellipse with affine transformation $(I,0)$ encoded as a 6D vector[0;0;1;0;0;1]
. Figure generated byvl_demo_frame
.This figure was generated by using the
vl_plotframe
function:A = eye(2) ; T = [0;0] ; f = [T ; A(:)] ; vl_plotframe(f) ; This particular oriented frame is conventionally deemed to be standard and, as shown in the code fragment above, it corresponds to the identity affine transformation. Since this ellipse is also a circle, the frame can equivalently be represented by an oriented circle with unit radius and null orientation:
radius = 1 ; theta = 0 ; f = [T ; radius ; theta] ; vl_plotframe(f) ; A positive rotation of the frame appears clockwise because the image coordinate system is left-handed (Y axis pointing downwards):
A frame rotated by 45 degrees; note that the rotation is clockwise: this is because the image uses a left-handed coordinate system (Y axis pointing downwards). Figure generated byvl_demo_frame
.radius = 1 ; theta = pi/4 ; f = [T ; radius ; theta] ; vl_plotframe(f) ; As indicated above, frames are often used to specify image transformations. In particular, oriented ellipses and oriented circles can be obtained by a unique affine transformation of the standard oriented circle shown above (the difference is that, different from oriented ellipses, oriented circles are not close with respect to all affine transformations).
For the oriented ellipse, this affine transformation $(A,T)$ is encoded explicitly in the
frame
vector used to represent it numerically. For example, the code fragmentf = [T ; A(:)] ; vl_plotframe(f) ; produces the plot
An oriented ellipse is specified as the affine transformation $(A,T)$ of the standard oriented frame shown above. Figure generated byvl_demo_frame
.Note that, when features extracted by a detector such as
vl_covdet
orvl_sift
, are normalized, this is done by applying the affine transformation which is the inverse of the one specified by the feature frame; in this way, in fact, the frame is transformed back to its standardized version.Similarly, unoriented frames can all be seen as affine transformations of the standard unoriented frame (the unit circle centered at the origin). In this case, however, the affine transformation $(A,T)$ is determined only up to a rotation $(AR, T)$. >When this ambiguity exists and an affine transformation $(A,T)$ needs to be selected, it is customary to choose $R$ such that the Y axis of the image is mapped onto itself (see below).
Converting between frame types
The function
vl_frame2oell
can be used to convert any frame type to an oriented ellipse.Since all oriented frames are special cases of oriented ellipses, this transformation is trivial for oriented circles and ellipses. On the other hand, rewriting unoriented frames as oriented ellipses requires assigning (arbitrarily) an orientation to them.
By default, when an arbitrary orientation has to be selected in the conversion, this is done in such a way that the affine transformation $(A,T)$ is upright. This means that $A$ maps the Y axis to itself:
\[ A\begin{bmatrix}1\\ 0\end{bmatrix} \propto \begin{bmatrix}1\\ 0\end{bmatrix}. \]This effect can be better understood by starting from some oriented frames, removing the orientation, and then using
vl_frame2oell
to generate oriented ellipses back: in the process, orientation information is lost and replaced by a conventional orientation:
Top: randomly sampled oriented ellipses. Middle: the same ellipses with the orientation removed. Bottom: oriented ellipses again, obtained by callingvl_frame2oell
; note that the orientation is upright. Figure generated byvl_demo_frame
.%tableofcontents; vlfeat/docsrc/tutorials/gmm.html 0000644 0001750 0001750 00000012730 12570775230 015731 0 ustar dima dimaThis tutorial shows how to extract Local Intensity Order Pattern (LIOP) deascriptors using VLFeat. LIOP is implemented in the
vl_liop
as well as invl_covdet
.LIOP descriptor computation
A LIOP descriptor can be computed from a square, gray scale image with and odd side length
patch
. This is usually not a restriction since local patches are obtained by cropping and warpinig an input image. The descriptor is computed using thevl_liop
function:descr = vl_covdet(patch) ; You can use the verbose option
verbose
if you wish to see the parametr and descriptor details.descr = vl_covdet(patch,'Verbose') ;
patch
can be a 3D array, with one image per 2D layer. In this case,descr
is a matrix with as many columns as images. LIOP is also integrated intovl_covdet
.
vl_liop
allows full customization of the LIOP descriptor parameters. These are discussed here. A parameter that is commonly tweaked is the intensity threshold to downweight unstalbe intensity order patterns in the descriptor computation. For exampledescr = vl_covdet(patch,'IntensityThreshold', 0.1) ; set this threshold to 0.1.
%tableofcontents; vlfeat/docsrc/tutorials/quickshift.html 0000644 0001750 0001750 00000007352 12570775230 017327 0 ustar dima dimaThis tutorial shows how to estiamte Gaussian mixture model using the VlFeat implementation of the Expectation Maximization (EM) algorithm.
A GMM is a collection of $K$ Gaussian distribution. Each distribution is called a mode of the GMM and represents a cluster of data points. In computer vision applications, GMM are often used to model dictionaries of visual words. One important application is the computation of Fisher vectors encodings.
Learning a GMM with expectation maximization
Consider a dataset containing 1000 randomly sampled 2D points:
numPoints = 1000 ; dimension = 2 ; data = rand(dimension,N) ; The goal is to fit a GMM to this data. This can be obtained by running the
vl_gmm
function, implementing the EM algorithm.numClusters = 30 ; [means, covariances, priors] = vl_gmm(data, numClusters) ; Here
means
,covariances
andpriors
are respectively the means $\mu_k$, diagonal covariance matrices $\Sigma_k$, and prior probabilities $\pi_k$ of thenumClusters
Gaussian modes.These modes can be visualized on the 2D plane by plotting ellipses corresponding to the equation: \[ \{ \bx: (\bx-\mu_k)^\top \Sigma_k^{-1} (\bx-\mu_k) = 1 \} \] for each of the modes. To this end, we can use the
vl_plotframe
:figure ; hold on ; plot(data(1,:),data(2,:),'r.') ; for i=1:numClusters vl_plotframe([means(:,i)' sigmas(1,i) 0 sigmas(2,i)]); end This results in the figure:
GMM fittting 2D random points.Diagonal covariance restriction
Note that the ellipses in the previous example are axis alligned. This is a restriction of the
vl_gmm
implementation that imposes covariance matrices to be diagonal.This is suitable for most computer vision applications, where estimating a full covariance matrix would be prohebitive due to the relative high dimensionality of the data. For example, when clustering SIFT features, the data has dimension 128, and each full covariance matrix would contain more than 8k parameters.
For this reason, it is sometimes desirable to globally decorrelated the data before learning a GMM mode. This can be obtained by pre-multiplying the data by the inverse of a square root of its covariance.
Initializing a GMM model before running EM
The EM algorithm is a local optimization method, and hence particularly sensitive to the initialization of the model. The simplest way to initiate the GMM is to pick
numClusters
data points at random as mode means, initialize the individual covariances as the covariance of the data, and assign equa prior probabilities to the modes. This is the default initialization method used byvl_gmm
.Alternatively, a user can specifiy manually the initial paramters of the GMM model by using the
custom
initalization method. To do so, set the'Initialization'
option to'Custom'
and also the options'InitMeans'
,'InitCovariances'
and'IniPriors'
to the desired values.A common approach to obtain an initial value for these parameters is to run KMeans first, as demonstrated in the following code snippet:
numClusters = 30; numData = 1000; dimension = 2; data = rand(dimension,numData); % Run KMeans to pre-cluster the data [initMeans, assignments] = vl_kmeans(data, numClusters, ... 'Algorithm','Lloyd', ... 'MaxNumIterations',5); initCovariances = zeros(dimension,numClusters); initPriors = zeros(1,numClusters); % Find the initial means, covariances and priors for i=1:numClusters data_k = data(:,assignments==i); initPriors(i) = size(data_k,2) / numClusters; if size(data_k,1) == 0 || size(data_k,2) == 0 initCovariances(:,i) = diag(cov(data')); else initCovariances(:,i) = diag(cov(data_k')); end end % Run EM starting from the given parameters [means,covariances,priors,ll,posteriors] = vl_gmm(data, numClusters, ... 'initialization','custom', ... 'InitMeans',initMeans, ... 'InitCovariances',initCovariances, ... 'InitPriors',initPriors); The demo scripts
vl_demo_gmm_2d
andvl_demo_gmm_3d
also produce cute colorized figures such as these: The figure shows how the estimated gaussian mixture looks like with and without the kmeans initialization.%tableofcontents; vlfeat/docsrc/tutorials/imdisttf.html 0000644 0001750 0001750 00000006241 12570775230 016774 0 ustar dima dimaQuick shift is a mode seeking algorithm (like mean shift) which instead of iteratively shifting each point towards a local mean instead forms a tree of links to the nearest neighbor which increases the density. For a more in-depth description of the algorithm, see our API reference for quick shift
Using quick shift to find superpixels
This demo shows quick shift in a simple superpixelization problem where we seek to segment this image:
The image we wish to segmentAs a feature vector, we choose the LAB colorspace representation of the image augmented with the x,y location of the pixel.
vl_quickseg
is a convenient wrapper function which takes care of the transformation of the image to LAB and performs segmentation, making our job as easy as:ratio = 0.5; kernelsize = 2; Iseg = vl_quickseg(I, ratio, kernelsize, maxdist); where
ratio
is the tradeoff between color importance and spatial importance (larger values give more importance to color),kernelsize
is the size of the kernel used to estimate the density, andmaxdist
is the maximum distance between points in the feature space that may be linked if the density is increased. The effect ofmaxdist
on the superpixelization. As we increasemaxdist
, superpixels become larger and larger since we can link less similar points. Top:maxdist=10
. Bottom:maxdist=20
.Multiple segmentations
Quick shift arranges all of the data points into a tree where parents in the tree are the nearest neighbors in the feature space which increase the estimate of the density. By imposing a limit on the distance between nearest neighbors (
maxdist
), we decrease the amount of computation required to search for the nearest neighbors. However, we also break our tree into a forest, because local modes of the density will now have no neighbor which is close enough in the feature space to form a link.In the previous section, we created a superpixel segmentation by taking each of the trees in this forest as a distinct cluster. However, since
maxdist
simply prevents new links from forming, the segmentation formed by everydist < maxdist
is contained in the result.vl_quickvis
lets us visualize this by running quick shift once and forming multiple segmentations by cutting links in the tree which are smaller and smaller.maxdist = 50; ndists = 10; Iedge = vl_quickvis(I, ratio, kernelsize, maxdist, ndists) imagesc(Iedge); axis equal off tight; colormap gray; A visualization of multiplemaxdist
thresholds on a single image. Here, boundaries are colored by the largestmaxdist
where the boundary is preserved.vlfeat/docsrc/using-gcc.html 0000644 0001750 0001750 00000001753 12420040400 014757 0 ustar dima dima The distance transform of an image
image
is defined asdt(u,v) = min image(u',v') + alpha (u'-u-u0)^2 + beta (v'-v'-v0)^2 u'v'The most common use of the image distance transform is to propagate the response of a feature detector to nearby image locations. This is used, for example, in the implementation of certain deformable part models or the computation of the Chamfer distance. In this tutorial, the image distance transform is used to compute the distance of each image pixel to the nearest element in an edge map, obtained from the Canny's edge detector. The code of this tutorial is located in the VLFeat folder in
toolbox/demo/vl_demo_imdisttf.m
.VLFeat implements the fast distance transform algorithm of Felzenszwalb and Huttelnocher [1], which has a linear time complexity in the number of image pixels.
Consider the edge map extracted by the MATLAB built-in Canny edge detector on one of VLFeat test images:
im = vl_impattern('roofs1') ; im = im(1:100,1:100,:) ; imSize = [size(im,1) size(im,2)] ; edges = zeros(imSize) + inf; edges(edge(rgb2gray(im), 'canny')) = 0 ; ![]()
Left: A detail of the source image. Right: Extracted Canny edges. Figure generated byvl_demo_imdisttf
.The edge map is preprocessed to assign value
-inf
to the pixels that do not contain an edge element ando
to the pixels that do. In this way, the distance transform of the image has for each pixel the distance to the nearest edge element, provided that one choosesalpha=beta=1
andv0=u0=0
in the definition. Since these are the default values for VLFeat implementations, the result an be computed by[distanceTransform, neighbors] = vl_imdisttf(single(edges)) ; The matrix
neighbors
contains for each pixel(u,v)
the index of the pixel(u',v')
where the maximum is attained in the definition of the distance transform. This allows to associate to know for each pixel which is the nearest edge element, not just its distance, as exemplified by the following figure:![]()
The distancesqrt(distanceTransform)
to the closest edge element (left) and arrows connecting pixels to their closest edge element (right). Figure generated byvl_demo_imdisttf
.References
[1] P. F. Felzenszwalb and D. P. Huttenlocher. Distance transforms of sampled functions. Technical report, Cornell University, 2004.
vlfeat/docsrc/vlfeat-website-preproc.xml 0000644 0001750 0001750 00000001772 12570775230 017354 0 ustar dima dima These instructions show how to setup a basic C++ project which uses the VLFeat library and the g++ compiler. Our project will consist of the following simple file, which we will refer to as
main.cpp
:extern "C" { #include <vl/generic.h> } int main (int argc, const char * argv[]) { VL_PRINT ("Hello world!") ; return 0; } Notice that the
extern "C"
is required for C++ projects. Compiling the project is straightforward. From the command prompt type:$ g++ main.cpp -o vlfeat-test -IVLROOT -LVLROOT/bin/a64/ -lvl In this example, replace
VLROOT
with the path to your VLFeat installation and replacea64
with your architecture (a64
for 64 bit linux,glx
for 32 bit linux).vlfeat/docsrc/doxygen.css 0000644 0001750 0001750 00000054124 12420040400 014401 0 ustar dima dima #context div.doxygen, #content .doxygen table, #content .doxygen div, #content .doxygen p, #content .doxygen dl { } #content .doxygen h1 { font-size: 150%; } #content .doxygen .title { font-size: 150%; font-weight: bold; margin: 10px 2px; } #content .doxygen h2 { font-size: 120%; } #content .doxygen h3 { font-size: 100%; } #content .doxygen h1, #content .doxygen h2, #content .doxygen h3, #content .doxygen h4, #content .doxygen h5, #content .doxygen h6 { -webkit-transition: text-shadow 0.5s linear; -moz-transition: text-shadow 0.5s linear; -ms-transition: text-shadow 0.5s linear; -o-transition: text-shadow 0.5s linear; transition: text-shadow 0.5s linear; margin-right: 15px; } #content .doxygen h1.glow, #content .doxygen h2.glow, #content .doxygen h3.glow, #content .doxygen h4.glow, #content .doxygen h5.glow, #content .doxygen h6.glow { text-shadow: 0 0 15px cyan; } #content .doxygen dt { font-weight: bold; } #content .doxygen div.multicol { -moz-column-gap: 1em; -webkit-column-gap: 1em; -moz-column-count: 3; -webkit-column-count: 3; } #content .doxygen p.startli, #content .doxygen p.startdd, #content .doxygen p.starttd { margin-top: 2px; } #content .doxygen p.endli { margin-bottom: 0px; } #content .doxygen p.enddd { margin-bottom: 4px; } #content .doxygen p.endtd { margin-bottom: 2px; } #content .doxygen caption { font-weight: bold; } #content .doxygen span.legend { font-size: 70%; text-align: center; } #content .doxygen h3.version { font-size: 90%; text-align: center; } #content .doxygen div.qindex, #content .doxygen div.navtab { background-color: #EBEFF6; border: 1px solid #A3B4D7; text-align: center; } #content .doxygen div.qindex, #content .doxygen div.navpath { width: 100%; line-height: 140%; } #content .doxygen div.navtab { margin-right: 15px; } #content .doxygen a { color: #3D578C; font-weight: normal; text-decoration: none; } #content .doxygen .contents a:visited { color: #4665A2; } #content .doxygen a:hover { text-decoration: underline; } #content .doxygen a.qindex { font-weight: bold; } #content .doxygen a.qindexHL { font-weight: bold; background-color: #9CAFD4; color: #ffffff; border: 1px double #869DCA; } #content .doxygen .contents a.qindexHL:visited { color: #ffffff; } #content .doxygen a.el { font-weight: bold; } #content .doxygen a.code, #content .doxygen a.code:visited { color: #4665A2; } #content .doxygen a.codeRef, #content .doxygen a.codeRef:visited { color: #4665A2; } #content .doxygen dl.el { margin-left: -1cm; } #content .doxygen pre.fragment { border: 1px solid #C4CFE5; background-color: #FBFCFD; padding: 6px 6px; margin: 0px 8px 0px 2px; overflow: auto; word-wrap: break-word; font-size: 9pt; line-height: 125%; font-family: monospace, fixed; font-size: 105%; } #content .doxygen div.fragment { padding: 4px; margin: 4px 0px 4px 0px ; background-color: #FBFCFD; border: 1px solid #C4CFE5; } #content .doxygen div.line { font-family: monospace, fixed; font-size: 13px; min-height: 13px; line-height: 1.5 ; text-wrap: unrestricted; white-space: -moz-pre-wrap; /* Moz */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ white-space: pre-wrap; /* CSS3 */ word-wrap: break-word; /* IE 5.5+ */ text-indent: -53px; padding-left: 53px; padding-bottom: 0px; margin: 0px; -webkit-transition-property: background-color, box-shadow; -webkit-transition-duration: 0.5s; -moz-transition-property: background-color, box-shadow; -moz-transition-duration: 0.5s; -ms-transition-property: background-color, box-shadow; -ms-transition-duration: 0.5s; -o-transition-property: background-color, box-shadow; -o-transition-duration: 0.5s; transition-property: background-color, box-shadow; transition-duration: 0.5s; } #content .doxygen div.line.glow { background-color: cyan; box-shadow: 0 0 10px cyan; } #content .doxygen span.lineno { padding-right: 4px; text-align: right; border-right: 2px solid #0F0; background-color: #E8E8E8; white-space: pre; } #content .doxygen span.lineno a { background-color: #D8D8D8; } #content .doxygen span.lineno a:hover { background-color: #C8C8C8; } #content .doxygen div.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px; padding: 0.2em; border: solid thin #333; border-radius: 0.5em; -webkit-border-radius: .5em; -moz-border-radius: .5em; box-shadow: 2px 2px 3px #999; -webkit-box-shadow: 2px 2px 3px #999; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; background-image: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#000000), color-stop(0.3, #444444)); background-image: -moz-linear-gradient(center top, #eeeeee 0%, #444444 40%, #000000); } #content .doxygen div.groupHeader { margin-left: 16px; margin-top: 12px; font-weight: bold; } #content .doxygen div.groupText { margin-left: 16px; font-style: italic; } #content .doxygen body { background-color: white; color: black; margin: 0; } #content .doxygen div.contents { margin-top: 10px; margin-left: 0px; margin-right: 0px; } #content .doxygen td.indexkey { background-color: #EBEFF6; font-weight: bold; border: 1px solid #C4CFE5; margin: 2px 0px 2px 0; padding: 2px 10px; white-space: nowrap; vertical-align: top; } #content .doxygen td.indexvalue { background-color: #EBEFF6; border: 1px solid #C4CFE5; padding: 2px 10px; margin: 2px 0px; } #content .doxygen tr.memlist { background-color: #EEF1F7; } #content .doxygen p.formulaDsp { text-align: center; } #content .doxygen img.formulaInl { vertical-align: middle; } #content .doxygen div.center { text-align: center; margin-top: 0px; margin-bottom: 0px; padding: 0px; } #content .doxygen div.center img { border: 0px; } #content .doxygen address.footer { text-align: right; padding-right: 12px; } #content .doxygen img.footer { border: 0px; vertical-align: middle; } #content .doxygen span.keyword { color: #008000; } #content .doxygen span.keywordtype { color: #604020; } #content .doxygen span.keywordflow { color: #e08000; } #content .doxygen span.comment { color: #800000; } #content .doxygen span.preprocessor { color: #806020; } #content .doxygen span.stringliteral { color: #002080; } #content .doxygen span.charliteral { color: #008080; } #content .doxygen span.vhdldigit { color: #ff00ff; } #content .doxygen span.vhdlchar { color: #000000; } #content .doxygen span.vhdlkeyword { color: #700070; } #content .doxygen span.vhdllogic { color: #ff0000; } #content .doxygen blockquote { background-color: #F7F8FB; border-left: 2px solid #9CAFD4; margin: 0 24px 0 4px; padding: 0 12px 0 16px; } #content .doxygen td.tiny { font-size: 75%; } #content .doxygen .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid #A3B4D7; } #content .doxygen th.dirtab { background: #EBEFF6; font-weight: bold; } #content .doxygen hr { height: 0px; border: none; border-top: 1px solid #4A6AAA; } #content .doxygen hr.footer { height: 1px; } #content .doxygen table.memberdecls { border-spacing: 0px; padding: 0px; } #content .doxygen .memberdecls td { -webkit-transition-property: background-color, box-shadow; -webkit-transition-duration: 0.5s; -moz-transition-property: background-color, box-shadow; -moz-transition-duration: 0.5s; -ms-transition-property: background-color, box-shadow; -ms-transition-duration: 0.5s; -o-transition-property: background-color, box-shadow; -o-transition-duration: 0.5s; transition-property: background-color, box-shadow; transition-duration: 0.5s; } #content .doxygen .memberdecls td.glow { background-color: cyan; box-shadow: 0 0 15px cyan; } #content .doxygen .mdescLeft, #content .doxygen .mdescRight, #content .doxygen .memItemLeft, #content .doxygen .memItemRight, #content .doxygen .memTemplItemLeft, #content .doxygen .memTemplItemRight, #content .doxygen .memTemplParams { background-color: #F9FAFC; border: none; margin: 4px; padding: 1px 0 0 8px; } #content .doxygen .mdescLeft, #content .doxygen .mdescRight { padding: 0px 8px 4px 8px; color: #555; } #content .doxygen .memItemLeft, #content .doxygen .memItemRight, #content .doxygen .memTemplParams { border-top: 1px solid #C4CFE5; } #content .doxygen .memItemLeft, #content .doxygen .memTemplItemLeft { white-space: nowrap; } #content .doxygen .memItemRight { width: 100%; } #content .doxygen .memTemplParams { color: #4665A2; white-space: nowrap; } #content .doxygen .memtemplate { font-size: 80%; color: #4665A2; font-weight: normal; margin-left: 9px; } #content .doxygen .memnav { background-color: #EBEFF6; border: 1px solid #A3B4D7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } #content .doxygen .mempage { width: 100%; } #content .doxygen .memitem { padding: 0; margin-bottom: 10px; margin-right: 5px; -webkit-transition: box-shadow 0.5s linear; -moz-transition: box-shadow 0.5s linear; -ms-transition: box-shadow 0.5s linear; -o-transition: box-shadow 0.5s linear; transition: box-shadow 0.5s linear; display: table !important; width: 100%; } #content .doxygen .memitem.glow { box-shadow: 0 0 15px cyan; } #content .doxygen .memname { font-weight: bold; margin-left: 6px; } #content .doxygen .memname td { vertical-align: bottom; } #content .doxygen .memproto, #content .doxygen dl.reflist dt { border-top: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; padding: 6px 0px 6px 0px; color: #253555; font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); background-image: url('nav_f.png'); background-repeat: repeat-x; background-color: #E2E8F2; /* opera specific markup */ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); border-top-right-radius: 4px; border-top-left-radius: 4px; /* firefox specific markup */ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; -moz-border-radius-topright: 4px; -moz-border-radius-topleft: 4px; /* webkit specific markup */ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); -webkit-border-top-right-radius: 4px; -webkit-border-top-left-radius: 4px; } #content .doxygen .memdoc, #content .doxygen dl.reflist dd { border-bottom: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; padding: 6px 10px 2px 10px; background-color: #FBFCFD; border-top-width: 0; background-image: url('nav_g.png'); background-repeat: repeat-x; background-color: #FFFFFF; /* opera specific markup */ border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); /* firefox specific markup */ -moz-border-radius-bottomleft: 4px; -moz-border-radius-bottomright: 4px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; /* webkit specific markup */ -webkit-border-bottom-left-radius: 4px; -webkit-border-bottom-right-radius: 4px; -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); } #content .doxygen dl.reflist dt { padding: 5px; } #content .doxygen dl.reflist dd { margin: 0px 0px 10px 0px; padding: 5px; } #content .doxygen .paramkey { text-align: right; } #content .doxygen .paramtype { white-space: nowrap; } #content .doxygen .paramname { color: #602020; white-space: nowrap; } #content .doxygen .paramname em { font-style: normal; } #content .doxygen .paramname code { line-height: 14px; } #content .doxygen .params, #content .doxygen .retval, #content .doxygen .exception, #content .doxygen .tparams { margin-left: 0px; padding-left: 0px; } #content .doxygen .params .paramname, #content .doxygen .retval .paramname { font-weight: bold; vertical-align: top; } #content .doxygen .params .paramtype { font-style: italic; vertical-align: top; } #content .doxygen .params .paramdir { font-family: "courier new", courier, monospace; vertical-align: top; } #content .doxygen table.mlabels { border-spacing: 0px; } #content .doxygen td.mlabels-left { width: 100%; padding: 0px; } #content .doxygen td.mlabels-right { vertical-align: bottom; padding: 0px; white-space: nowrap; } #content .doxygen span.mlabels { margin-left: 8px; } #content .doxygen span.mlabel { background-color: #728DC1; border-top: 1px solid #5373B4; border-left: 1px solid #5373B4; border-right: 1px solid #C4CFE5; border-bottom: 1px solid #C4CFE5; text-shadow: none; color: white; margin-right: 4px; padding: 2px 3px; border-radius: 3px; font-size: 7pt; white-space: nowrap; } #content .doxygen div.directory { margin: 10px 0px; border-top: 1px solid #A8B8D9; border-bottom: 1px solid #A8B8D9; width: 100%; } #content .doxygen .directory table { border-collapse: collapse; } #content .doxygen .directory td { margin: 0px; padding: 0px; vertical-align: top; } #content .doxygen .directory td.entry { white-space: nowrap; padding-right: 6px; } #content .doxygen .directory td.entry a { outline: none; } #content .doxygen .directory td.entry a img { border: none; } #content .doxygen .directory td.desc { width: 100%; padding-left: 6px; padding-right: 6px; border-left: 1px solid rgba(0, 0, 0, 0.05); } #content .doxygen .directory tr.even { padding-left: 6px; background-color: #F7F8FB; } #content .doxygen .directory img { vertical-align: -30%; } #content .doxygen .directory .levels { white-space: nowrap; width: 100%; text-align: right; font-size: 9pt; } #content .doxygen .directory .levels span { cursor: pointer; padding-left: 2px; padding-right: 2px; color: #3D578C; } #content .doxygen div.dynheader { margin-top: 8px; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #content .doxygen address { font-style: normal; color: #2A3D61; } #content .doxygen table.doxtable { border-collapse: collapse; margin-top: 4px; margin-bottom: 4px; } #content .doxygen table.doxtable td, #content .doxygen table.doxtable th { border: 1px solid #2D4068; padding: 3px 7px 2px; } #content .doxygen table.doxtable th { background-color: #374F7F; color: #FFFFFF; font-size: 110%; padding-bottom: 4px; padding-top: 5px; } #content .doxygen table.fieldtable { width: 100%; margin-bottom: 10px; border: 1px solid #A8B8D9; border-spacing: 0px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } #content .doxygen .fieldtable td, #content .doxygen .fieldtable th { padding: 3px 7px 2px; } #content .doxygen .fieldtable td.fieldtype, #content .doxygen .fieldtable td.fieldname { white-space: nowrap; border-right: 1px solid #A8B8D9; border-bottom: 1px solid #A8B8D9; vertical-align: top; } #content .doxygen .fieldtable td.fielddoc { border-bottom: 1px solid #A8B8D9; width: 100%; } #content .doxygen .fieldtable tr:last-child td { border-bottom: none; } #content .doxygen .fieldtable th { background-image: url('nav_f.png'); background-repeat: repeat-x; background-color: #E2E8F2; font-size: 90%; color: #253555; padding-bottom: 4px; padding-top: 5px; text-align: left; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom: 1px solid #A8B8D9; } #content .doxygen .tabsearch { top: 0px; left: 10px; height: 36px; background-image: url('tab_b.png'); z-index: 101; overflow: hidden; font-size: 13px; } #content .doxygen .navpath ul { font-size: 11px; background-image: url('tab_b.png'); background-repeat: repeat-x; height: 30px; line-height: 30px; color: #8AA0CC; border: solid 1px #C2CDE4; overflow: hidden; margin: 0px; padding: 0px; } #content .doxygen .navpath li { list-style-type: none; float: left; padding-left: 10px; padding-right: 15px; background-image: url('bc_s.png'); background-repeat: no-repeat; background-position: right; color: #364D7C; } #content .doxygen .navpath li.navelem a { height: 32px; display: block; text-decoration: none; outline: none; } #content .doxygen .navpath li.navelem a:hover { color: #6884BD; } #content .doxygen .navpath li.footer { list-style-type: none; float: right; padding-left: 10px; padding-right: 15px; background-image: none; background-repeat: no-repeat; background-position: right; color: #364D7C; font-size: 8pt; } #content .doxygen div.summary { float: right; font-size: 8pt; padding-right: 5px; width: 50%; text-align: right; } #content .doxygen div.summary a { white-space: nowrap; } #content .doxygen div.ingroups { font-size: 8pt; width: 50%; text-align: left; } #content .doxygen div.ingroups a { white-space: nowrap; } #content .doxygen div.header { background-image: url('nav_h.png'); background-repeat: repeat-x; background-color: #F9FAFC; margin: 0px; border-bottom: 1px solid #C4CFE5; } #content .doxygen div.headertitle { padding: 5px 5px 5px 7px; } #content .doxygen dl { padding: 0 0 0 10px; } #content .doxygen dl.section { margin-left: 0px; padding-left: 0px; } #content .doxygen dl.note { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #D0C000; } #content .doxygen dl.warning, #content .doxygen dl.attention { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #FF0000; } #content .doxygen dl.pre, #content .doxygen dl.post, #content .doxygen dl.invariant { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #00D000; } #content .doxygen dl.deprecated { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #505050; } #content .doxygen dl.todo { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #00C0E0; } #content .doxygen dl.test { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #3030E0; } #content .doxygen dl.bug { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #C08050; } #content .doxygen dl.section dd { margin-bottom: 6px; } #content .doxygen #projectlogo { text-align: center; vertical-align: bottom; border-collapse: separate; } #content .doxygen #projectlogo img { border: 0px none; } #content .doxygen #projectname { font: 300% Tahoma, Arial, sans-serif; margin: 0px; padding: 2px 0px; } #content .doxygen #projectbrief { font: 120% Tahoma, Arial, sans-serif; margin: 0px; padding: 0px; } #content .doxygen #projectnumber { font: 50% Tahoma, Arial, sans-serif; margin: 0px; padding: 0px; } #content .doxygen #titlearea { padding: 0px; margin: 0px; width: 100%; border-bottom: 1px solid #5373B4; } #content .doxygen .image { text-align: center; } #content .doxygen .dotgraph { text-align: center; } #content .doxygen .mscgraph { text-align: center; } #content .doxygen .caption { font-weight: bold; } #content .doxygen div.zoom { border: 1px solid #90A5CE; } #content .doxygen dl.citelist { margin-bottom: 50px; } #content .doxygen dl.citelist dt { color: #334975; float: left; font-weight: bold; margin-right: 10px; padding: 5px; } #content .doxygen dl.citelist dd { margin: 2px 0; padding: 5px 0; } #content .doxygen div.toc { padding: 14px 25px; background-color: #F4F6FA; border: 1px solid #D8DFEE; border-radius: 3px 3px 3px 3px; float: right; height: auto; margin: 0px 0px 10px 10px; width: 200px; } #content .doxygen div.toc li { background: url("bdwn.png") no-repeat scroll 0 5px transparent; font: 10px/1.2 Verdana, DejaVu Sans, Geneva, sans-serif; margin-top: 5px; padding-left: 10px; padding-top: 2px; } #content .doxygen div.toc h3 { font: bold 12px/1.2 Arial, FreeSans, sans-serif; color: #4665A2; border-bottom: 0 none; margin: 0; } #content .doxygen div.toc ul { list-style: none outside none; border: medium none; padding: 0px; } #content .doxygen div.toc li.level1 { margin-left: 0px; } #content .doxygen div.toc li.level2 { margin-left: 15px; } #content .doxygen div.toc li.level3 { margin-left: 30px; } #content .doxygen div.toc li.level4 { margin-left: 45px; } #content .doxygen .inherit_header { font-weight: bold; color: gray; cursor: pointer; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #content .doxygen .inherit_header td { padding: 6px 0px 2px 5px; } #content .doxygen .inherit { display: none; } #content .doxygen tr.heading h2 { margin-top: 12px; margin-bottom: 4px; } @media print { #content .doxygen #top { display: none; } #content .doxygen #side-nav { display: none; } #content .doxygen #nav-path { display: none; } #content .doxygen body { overflow: visible; } #content .doxygen h1, #content .doxygen h2, #content .doxygen h3, #content .doxygen h4, #content .doxygen h5, #content .doxygen h6 { page-break-after: avoid; } #content .doxygen .summary { display: none; } #content .doxygen .memitem { page-break-inside: avoid; } #content .doxygen #doc-content { margin-left: 0 !important; height: auto !important; width: auto !important; overflow: inherit; display: inline; } } /* missing in original doxygen.css ? */ #content .doxygen div.tabs, #content .doxygen div.tabs2, #content .doxygen div.tabs3, #content .doxygen div.tabs4 { padding: 0 ; margin: 0 ; border: 1px solid white ; font-size: .9em ; } #content .doxygen ul.tablist { display: block ; width: 100% ; margin: 5px 0 ; padding: 0 ; border-bottom: 2px solid #aaa ; } #content .doxygen ul.tablist li { display: inline-block ; margin: 0px 4px ; padding: 5px ; border: 1px solid #aaa ; border-bottom: none ; background-color: #f6f6f6 ; } #content .doxygen ul.tablist li.current { background-color: inherit ; } #content .doxygen ul.tablist li a { text-decoration : none ; color: black ; } #content .doxygen ul.tablist li.current a { font-weight: bold ; } vlfeat/docsrc/using-vsexpress.html 0000644 0001750 0001750 00000005312 12420040400 016260 0 ustar dima dima vlfeat/docsrc/vlfeat-website.xml 0000644 0001750 0001750 00000002512 12570775230 015675 0 ustar dima dima These instructions show how to setup a basic VLFeat project with Visual C++ Express 2008 on Windows XP (32 bit). Instructions for other versions of Visual Studio should be similar.
First, we create a new project called
vlfeat-client
. Open Visual C++ Express 2008 and select File > New > Project and choose General > Empty Project. Give your project a name and location (herevlfeat-client
) and click OK.![]()
![]()
Next, we have to modify the project properties to include the VLFeat library and include directories. Right click on the project and select properties.
![]()
We want these settings to apply to both Debug and Release builds, so switch to all configurations.
![]()
Add an additional include path which points to the root of the VLFeat folder:
![]()
Add an additional library include path pointing to the
bin/w32
folder in the distribution, and addvl.dll
as a dependency:![]()
![]()
This will allow us to compile, but we will not be able to run, getting because
vl.dll
will not be found:![]()
To remedy this, we add a post-build step which copies vl.dll to the debug or release folder. Since this only needs to be done once for each project, we could instead copy the file manually.
![]()
Now that we have created our project, add a new .cpp file (right click on Source Files and choose Add > New Item) with this code:
extern "C" { #include <vl/generic.h> } int main (int argc, const char * argv[]) { VL_PRINT ("Hello world!\n") ; return 0; } Build and run the project (Ctrl+F5). It should run correctly, and you should see this:
![]()
vlfeat/docsrc/vlfeat.css 0000644 0001750 0001750 00000023030 12570775701 014226 0 ustar dima dima /* div, p, ul, li, ol, img {border: 1px solid red ;} */ html, body, div, img, dl { margin: 0px ; padding: 0px ; border-style: none ; /* ie again */ } html { } body { font-size: 14px ; line-height: 18px ; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif ; background-color: #f6f6f6 ; } table { font: inherit ; color: inherit ; } h1, h2, h3, h4, h5, h6 { font-weight: bold ; } a { color: #004fdc; } a.plain { text-decoration: inherit ! important ; color: inherit ! important ; } b { color: rgb(40,40,40) ; } pre, code { font-family: 'Bitstream Vera Sans Mono', monospace ; } code { color: #BA2121 ; } code a { font-weight: bold ; text-decoration: none ; color: inherit ! important ; } .clear { clear: both ; margin: 0px ; padding: 0px ; font-size: 1px ; line-height: 1px ; } .standout { font-style: italic ; color: red ! important ; } .clearfix { display: inline-block ; width: 100% ; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Sidebar */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #sidebar { width: 920px ; padding: 0 30px ; margin: 0 ; margin-left: auto ; margin-right: auto ; color: white ; font-weight: bold ; } #sidebar a { color: inherit ! important ; text-decoration: none ; } #sidebar ul { margin: 0 ; padding: 0 ; } /* t r b l */ #sidebar ul li { display: inline-block ; color: white ; position: relative ; list-style-type: none ; padding: 10px 15px 10px 15px ; margin: 0px 11px 0px -15px ; font-size: 14px ; line-height: 14px ; } #sidebar ul li.active { background-color: rgb(207,122,48) ; } #sidebar ul li ul { position: absolute ; width: 513px ; top: 34px ; left: -1px ; visibility: hidden ; font-size: 0px ; } #sidebar ul li ul li { width: 225px ; margin: 0 ; margin-right: -1px ; border: 1px solid white ; border-bottom: none ; background-color: #183a60 ; font-size: 12px ; } #sidebar ul li ul li ul { top: -1px ; left: 223px ; width: 225px ; } #sidebar li:hover > ul { visibility: visible ; } #sidebar li:hover { color: rgb(207,122,48) ; } #sidebar li.active:hover { color: white ; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Header */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #header-section { background-color: #183a60 ; } #header { max-width: 920px ; margin-left: auto ; margin-right: auto ; padding: 20px 30px ; } #header .searchbox { float: right ; margin-right: 1em ; margin-top: auto ; margin-bottom: auto ; width: 25em ; } #header h1 { margin: 0 ; color: white ; font-family: 'Trebuchet MS', Helvetica, sans-serif ; } #header h1 a { text-decoration: none ; color: white ; } #dotorg { color: #AAA ; } #google { float: right ; width: 20em ; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Head banner */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #headbanner-section { border-bottom: 1px solid #DDD ; } #headbanner { max-width: 920px ; margin-left: auto ; margin-right: auto ; padding: 7px 30px ; color: #5a5a5a ; font-weight: bold ; font-size: 14px ; } #headbanner a { text-decoration: inherit ! important ; color: inherit ! important ; } #headbanner span.page { } #headbanner span.separator { padding-left: 10px ; padding-right: 10px ; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Content */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #content-section { background-color: white ; } #content-wrapper { max-width: 920px ; margin-left: auto ; margin-right: auto ; padding: 0 30px ; } #content { overflow: hidden ; } #content h1, #content h2, #content h3, #content h4, #content h5, #content h6 { margin: 1em 0 ; margin-top: 1.7em ; } #content h1 {font-size:1.4em; margin-bottom: 0.5em;} #content h2 {font-size:1.3em; margin-bottom: 0.5em;} #content h3 {font-size:1.2em; margin-bottom: 0.5em;} #content h4 {font-size:1.1em; margin-bottom: 0.5em;} #content h5 {font-size:1.0em; margin-bottom: 0.5em;} #content h6 {font-size:1.0em; margin-bottom: 0.5em;} #content p, #content blockquote, #content div.figure, #content div.p { margin: 1em 0 ; } #content blockquote { margin: 1em ; font-style: italic ; } #content pre { margin: 1em 0 ; padding: 0 ; } #content div.highlight { margin: 1em 0 ; background-color: #f6f6f6 ; border-top: 1px solid #DDD ; border-bottom: 1px solid #DDD ; } #content div.highlight pre { margin: 0px ; padding: 0.5em ; padding-left: 1em ; margin-right: 5em ; } #content ul, #content ol { margin-left: 0; padding-left: 0 ; } #content li { margin-left: 1.2em ; padding-left: 0 ; } #content ol li { margin-left: 2em ; } #content dt { font-weight: bold ; text-align: left ; } #content dd { display: block ; margin: 0.25em 0 ; padding-left: 2em ; } #content dd p, #content dd ul { margin-top: 0 ; } #content .centered { display: block ; margin-left: 2em ; } #content div.figure { margin-top: 1em ; margin-bottom: 1em ; text-align: center ; } #content div.caption { font-family: Lucida, Helvetica, sans-serif ; font-style: italic ; } /* for buggy IE 6 */ #content div.caption span.content { display: inline ; zoom: 1 ; } #content div.caption span.content { display: inline-block ; text-align: left ; max-width: 40em ; } #content div.box { background-color: #f6f6f6 ; border: 1px solid #DDD ; padding: 0.5em ; } #content table.onecol td { width: 100% ; } #content table.twocols td { width: 50% ; } #content table.threecols td { width: 33% ; } #content table.boxes { min-width: 100% ; border-collapse: separate ; border-spacing: 10px ; margin: -10px ; padding: 0em ; box-sizing:border-box ; /* avoids exceeding 100% width */ } #content table.boxes td { vertical-align: top ; background-color: #f6f6f6 ; border: 1px solid #DDD ; padding: 0.5em ; } #content .boxes h1 { font-size: 1.2em ; margin: 0px ; } #content .boxes ul { margin-top: 0.25em ; margin-bottom: 0.5em ; } #content .boxes p { margin-top: 0.25em ; margin-bottom: 0.5em ; padding: 0px ; } #content img.image-right { float: right ; } #content div.parbox { border: 1px dotted #333 ; padding: 0em 1em ; margin-right: 10em ; } #content div.parbox p, #content div.parbox blockquote, #content div.pargox div.figure, #content dd blockquote { padding-right: 0em ; } #content ul.text { padding-right: 10em ; } #content ul.text li { margin-top: 1em ; margin-bottom: 1em ; } #pagebody { background-color: #eee ; display: inline-block; width: 100%; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Footer */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #footer-section { clear: both ; border-top: 1px solid #DDD ; } #footer { text-align: center ; padding: 0.5em ; font-size: 0.9em ; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Mdoc */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #content div.mdoc ul.breadcrumb { float: right ; width: 100% ; margin: 1em 0 ; padding: 0 ; border-bottom: 1px solid #aaa ; } #content div.mdoc ul.breadcrumb:after { content: "." ; display: block ; height: 0 ; clear: right ; visibility: hidden ; } #content div.mdoc ul.breadcrumb li { display: block ; float: left ; width: 4em ; margin: 0 0.5em ; padding: .2em ; font-size: .9em ; font-weight: bold ; border-top: 2px solid #aaa ; border-left: 2px solid #aaa ; border-right: 2px solid #aaa ; text-align: center ; } #content div.mdoc ul.breadcrumb a { text-decoration : none ; color: black ; } #content div.mdoc span.defaults { font-weight: normal ; color: green ; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Toc */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #content div.toc { padding: 14px 25px; background-color: #F4F6FA; border: 1px solid #D8DFEE; border-radius: 3px 3px 3px 3px; float: right; height: auto; margin: 1em 0px 10px 10px; width: 200px; } #content div.toc li { background: url("api/bdwn.png") no-repeat scroll 0 5px transparent; font: 10px/1.2 Verdana, DejaVu Sans, Geneva, sans-serif; margin-top: 5px; padding-left: 10px; padding-top: 2px; } #content div.toc h3 { font: bold 12px/1.2 Arial, FreeSans, sans-serif; color: #4665A2; border-bottom: 0 none; margin: 0; } #content div.toc ul { list-style: none outside none; border: medium none; padding: 0px; } #content div.toc li.level1 { margin-left: 0px; } #content div.toc li.level2 { margin-left: 15px; } #content div.toc li.level3 { margin-left: 30px; } #content div.toc li.level4 { margin-left: 45px; } vlfeat/docsrc/images/ 0000755 0001750 0001750 00000000000 12570775230 013477 5 ustar dima dima vlfeat/docsrc/images/vl_blue_large.pxm 0000644 0001750 0001750 00000556275 12570775230 017053 0 ustar dima dima PXMDMETAi bplist00Ô€X$versionX$objectsY$archiverT$top † ¯,-./0123456789:;<=>?@ABCHLSVZ[\jklmnouvwz{|U$nullÓ ,WNS.keysZNS.objectsV$class¯ €€€€€€€€ € €€€ €€€¯ !"# &"("*+€€€€€€€€€€€€€€€€+_3PTImageIOFormatBasicMetaBitsPerComponentInfoInfoKey_+PTImageIOFormatBasicMetaDocumentSizeInfoKey_.PTImageIOFormatBasicMetaResolutionUnitsInfoKey_/PTImageIOFormatBasicMetaGroupLayersCountInfoKey_-PTImageIOFormatBasicMetaColorspaceNameInfoKey_0PTImageIOFormatBasicMetaBitmapLayersCountInfoKey_)PTImageIOFormatBasicMetaDataAmountInfoKey_.PTImageIOFormatBasicMetaLayerMasksCountInfoKey_0PTImageIOFormatBasicMetaVectorLayersCountInfoKey_)PTImageIOFormatBasicMetaLayerNamesInfoKey_.PTImageIOFormatBasicMetaTextLayersCountInfoKey_1PTImageIOFormatBasicMetaNumberOfComponentsInfoKey_.PTImageIOFormatBasicMetaColorspaceModelInfoKey_)PTImageIOFormatBasicMetaResolutionInfoKey_&PTImageIOFormatBasicMetaVersionInfoKeyZ{512, 512} _sRGB IEC61966-2.1 Ò DG¢EF€€€ÒIJKYNS.string€RvlÒMNOPZ$classnameX$classes_NSMutableString£OQRXNSStringXNSObjectÒIJU€_Background LayerÒMNWX^NSMutableArray£WYRWNSArray#@R Ó ]c,¥^_`ab€ €!€"€#€$¥de^ge€%€)€ €*€)€+_PTImageIOPlatformMacOS_%PTImageIOFormatDocumentVersionInfoKey_-PTImageIOFormatDocumentSavedOnPlatformInfoKey_1PTImageIOFormatDocumentSavedWithAppVersionInfoKey_5PTImageIOFormatDocumentMinimumSupportedVersionInfoKeyÓ prt¡q€&¡s€'€(_7PTImageIOFormatDocumentRequiresMinimumAppVersionInfoKeyU3.1.1ÒMNxy\NSDictionary¢xRS1.4S3.2ÒMN}~_NSMutableDictionary£}xR_NSKeyedArchiverÑ‚Troot€ # - 2 7 f l s { † Ÿ ¡ £ ¥ § © « ¯ ± ³ µ · ¹ » ½ Ï Ñ Ó Õ × Ù Û Ý ß á ã å ç é ë í ï%S„¶æEv©Õ:k—ÀÂÍÏÑåçìñôöøúÿ '9=FOTVin}‰‹”›¡£¥§©«±³µ·¹»½Öþ.bš¡£¥§©«åëðý #'9<A ƒ CPK ´7_ ð ð document/infoSQLite format 3 @ -â% ü ì CÁ´ ì !!ktablelayer_infolayer_infoCREATE TABLE layer_info (layer_uuid TEXT, name TEXT, value BLOB, UNIQUE (layer_uuid, name) ON CONFLICT REPLACE)3G! indexsqlite_autoindex_layer_info_1layer_info))Stabledocument_layerdocument_layerCREATE TABLE document_layer (layer_uuid TEXT, parent_uuid TEXT, index_at_parent INTEGER, type TEXT)|''7tabledocument_infodocument_infoCREATE TABLE document_info (name TEXT, value BLOB, UNIQUE (name) ON CONFLICT REPLACE)9M' indexsqlite_autoindex_document_info_1document_info ö ûö½‹R 7ePTImageIOFormatDocumentResolutionSizeInfoKey{72, 72}0g PTImageIOFormatDocumentResolutionUnitsInfoKey‘]¡JPTImageIOFormatDocumentCustomDataInfoKeybplist00ÔstX$versionX$objectsY$archiverT$top † ¯! !"#$%&',45678?GHLOPXYZ[_cdnopU$nullÓ WNS.keysZNS.objectsV$class¨ €€€€€€€€ ¨€ €€€€€€€ €__LAYERGROUPS_EXPANSION_STATES___DOCUMENT_SLICES___LAYERS_VISIBLE_RECT___DOCUMENT_SLICES_INFO___LAYERS_SELECTION___DOCUMENT_WINDOW_RECT__PXRulersMetadataKey\_PRINT_INFO_Ò (+¢)*€€€Ó -0¢./€€ ¢12€€€W_STATE_T_ID__;1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EÒ9:; These man pages describe VLFeat command line utilities.
\NSDictionaryXNSObjectÓ @C¢./€€ ¢1E€€€_;926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22Ò9:IJ^NSMutableArray£IK>WNSArrayÒ M+ €_{{0, 0}, {265, 501}}Ó QT¢RS€€¢UU€€€_PXSlicesPreviewEnabledKey_PXSlicesVisibleKey Ò\]^WNS.dataO bplist00ÔX$versionX$objectsY$archiverT$top † £U$nullÔ ZNSLocationV$class\NSRangeCountXNSLength €ÒZ$classnameX$classesZNSIndexSet¢ZNSIndexSetXNSObject_NSKeyedArchiverÑTroot€#-27;AJU\irtvx}ˆ‘œŸª³ÅÈÍ Ï€Ò9:`a]NSMutableData£`b>VNSData_{{471, 121}, {735, 695}}Ó ei£RgS€€€£UkU€€€€_PXRulersMeasurementUnitKey Ò\q^O”bplist00Ô=>X$versionX$objectsY$archiverT$top † ¯ #$%&'()*+,-./0129U$nullÒ V$class\NSAttributes€€Ó "WNS.keysZNS.objects¨€€€€€€€ € ¨ !€€€ €€€€€€_NSHorizontallyCentered]NSRightMargin\NSLeftMargin_NSHorizonalPagination_NSVerticalPagination_NSVerticallyCentered[NSTopMargin^NSBottomMargin "B "B "B´ "B´ Ò3456Z$classnameX$classes_NSMutableDictionary£578\NSDictionaryXNSObjectÒ34:;[NSPrintInfo¢<8[NSPrintInfo_NSKeyedArchiverÑ?@Troot€ # - 2 7 N T Y ` m o q x € ‹ ” – ˜ š œ ž ¢ ¤ ¯ ± ³ µ · ¹ » ½ ¿ Ø æ ó"9ETUZ_achmr}†œ ¶»ÇÊÖèëð A ò€_NSKeyedArchiverÑuvTroot€ # - 2 7 [ a h p { ‚ ‹ ‘ “ • — ™ › ¤ ¦ ¨ ª ¬ ® ° ² ´ ¶ × ë1J`mruwy{‚…‡‰ŒŽ’šŸ Þãî÷ '.1358:<>|”œ¡¢¤»ÂÅÇÉÌÎÐÒî !&48?Zaegikoqsuw”–›35GJO w Q2iPTImageIOFormatDocumentBitsPerComponentInfoKey8_MPTImageIOFormatDocumentIDInfoKey31E82A46-2527-443B-885D-769F43A1464E-33484-00049CB67741BC2Eƒo†ZPTImageIOFormatDocumentViewingOptionsInfoKey_PTImageIOPlatformMacOSbplist00ÔX$versionX$objectsY$archiverT$top † §U$nullÓ WNS.keysZNS.objectsV$class¢ €€¢€€€_0PTImageIOFormatDocumentViewingVisibleRectInfoKey_)PTImageIOFormatDocumentViewingZoomInfoKey_{{-240, -197}, {735, 649}}"? ÒZ$classnameX$classes\NSDictionary¢XNSObject_NSKeyedArchiverÑ Troot€ # - 2 7 ? E L T _ f i k m p r t v © Õ ò ÷ ü );>C ! E„+cˆPTImageIOFormatDocumentLayersLinkingInfoKeybplist00Ô&'X$versionX$objectsY$archiverT$top † ¨"U$nullÓ WNS.keysZNS.objectsV$class¢ €€¢€€€_;926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22_;1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EÒ €ÒZ$classnameX$classes^NSMutableArray£WNSArrayXNSObjectÒ €Ò#$_NSMutableDictionary£#%\NSDictionary_NSKeyedArchiverÑ()Troot€ # - 2 7 @ F M U ` g j l n q s u w µ ó ø ù û #'/8=>@E[_l~† * „0 âwcÑ O> Ñ ·ˆ 2iPTImageIOFormatDocumentColorsyncProfileInfoKey4mPTImageIOFormatDocumentNumberOfComponentsInfoKey2iPTImageIOFormatDocumentBitmapDataFormatInfoKey *YPTImageIOFormatDocumentSaveDateInfoKey4mPTImageIOFormatDocumentFileVersionSupportInfoKey&QPTImageIOFormatDocumentSizeInfoKey 8uPTImageIOFormatDocumentOriginalExifDictionaryInfoKey (UPTImageIOFormatDocumentGuidesInfoKey0ePTImageIOFormatDocumentResolutionSizeInfoKey1gPTImageIOFormatDocumentResolutionUnitsInfoKey,]PTImageIOFormatDocumentCustomDataInfoKey2iPTImageIOFormatDocumentBitsPerComponentInfoKey$MPTImageIOFormatDocumentIDInfoKeyHPTImageIOFormatDocumentViewingOptionsInfoKey_PTImageIOPlatformMacOS.c PTImageIOFormatDocumentLayersLinkingInfoKey ( “( i ]1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93Ecom.pixelmatorteam.pixelmator.layer.textk a926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22com.pixelmatorteam.pixelmator.layer.bitmap ì ûöñì pm926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerPreservesTransparencyInfoKey|u926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerBitmapDataChangeTimestampInfoKeyA¹Á~Š&ph] 926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerHasBitmapDataInfoKeyoK-926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerNameInf € M€ x ã ²ê¶ IÀ «6@w ÝN å i]1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerHasBitmapDataInfoKeybO1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerOriginInfoKeyh[1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerBlendingModeInfoKey`K1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerSizeInfoKey`K1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerNameInfoKeyj_1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerIsClippingMaskInfoKeyeU1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerIsVisibleInfoKeyh[1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerSpecificDataInfoKeycQ1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EPTImageIOFormatLayerOpacityInfoKey `K926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerSizeInfoKeyeU926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerIsVisibleInfoKeybO926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerOriginInfoKey j_926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerIsClippingMaskInfoKey h[926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerBlendingModeInfoKeylc926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerBitmapDataFormatInfoKeycQ926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerOpacityInfoKeyh[926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerSpecificDataInfoKeyqm926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerPreservesTransparencyInfoKeyuu926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerBitmapDataChangeTimestampInfoKeyi]926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerHasBitmapDataInfoKey_K 926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22PTImageIOFormatLayerNameInfoKey R ÒàK½‹R 7ePTImageIOFormatDocumentResolutionSizeInfoKey{72, 72}0g PTImageIOFormatDocumentResolutionUnitsInfoKey‘]¡JPTImageIOFormatDocumentCustomDataInfoKeybplist00ÔstX$versionX$objectsY$archiverT$top † ¯! !"#$%&',45678?GHLOPXYZ[_cdnopU$nullÓ WNS.keysZNS.objectsV$class¨ €€€€€€€€ ¨€ €€€€€€€ €__LAYERGROUPS_EXPANSION_STATES___DOCUMENT_SLICES___LAYERS_VISIBLE_RECT___DOCUMENT_SLICES_INFO___LAYERS_SELECTION___DOCUMENT_WINDOW_RECT__PXRulersMetadataKey\_PRINT_INFO_Ò (+¢)*€€€Ó -0¢./€€ ¢12€€€W_STATE_T_ID__;1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EÒ9:; \NSDictionaryXNSObjectÓ @C¢./€€ ¢1E€€€_;926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22Ò9:IJ^NSMutableArray£IK>WNSArrayÒ M+ €_{{0, 0}, {265, 501}}Ó QT¢RS€€¢UU€€€_PXSlicesPreviewEnabledKey_PXSlicesVisibleKey Ò\]^WNS.dataO bplist00ÔX$versionX$objectsY$archiverT$top † £U$nullÔ ZNSLocationV$class\NSRangeCountXNSLength €ÒZ$classnameX$classesZNSIndexSet¢ZNSIndexSetXNSObject_NSKeyedArchiverÑTroot€#-27;AJU\irtvx}ˆ‘œŸª³ÅÈÍ Ï€Ò9:`a]NSMutableData£`b>VNSData_{{471, 121}, {735, 695}}Ó ei£RgS€€€£UkU€€€€_PXRulersMeasurementUnitKey Ò\q^O”bplist00Ô=>X$versionX$objectsY$archiverT$top † ¯ #$%&'()*+,-./0129U$nullÒ V$class\NSAttributes€€Ó "WNS.keysZNS.objects¨€€€€€€€ € ¨ !€€€ €€€€€€_NSHorizontallyCentered]NSRightMargin\NSLeftMargin_NSHorizonalPagination_NSVerticalPagination_NSVerticallyCentered[NSTopMargin^NSBottomMargin "B "B "B´ "B´ Ò3456Z$classnameX$classes_NSMutableDictionary£578\NSDictionaryXNSObjectÒ34:;[NSPrintInfo¢<8[NSPrintInfo_NSKeyedArchiverÑ?@Troot€ # - 2 7 N T Y ` m o q x € ‹ ” – ˜ š œ ž ¢ ¤ ¯ ± ³ µ · ¹ » ½ ¿ Ø æ ó"9ETUZ_achmr}†œ ¶»ÇÊÖèëð A ò€_NSKeyedArchiverÑuvTroot€ # - 2 7 [ a h p { ‚ ‹ ‘ “ • — ™ › ¤ ¦ ¨ ª ¬ ® ° ² ´ ¶ × ë1J`mruwy{‚…‡‰ŒŽ’šŸ Þãî÷ '.1358:<>|”œ¡¢¤»ÂÅÇÉÌÎÐÒî !&48?Zaegikoqsuw”–›35GJO w Q2iPTImageIOFormatDocumentBitsPerComponentInfoKey8_MPTImageIOFormatDocumentIDInfoKey31E82A46-2527-443B-885D-769F43A1464E-33484-00049CB67741BC2Eƒo†ZPTImageIOFormatDocumentViewingOptionsInfoKey_PTImageIOPlatformMacOSbplist00ÔX$versionX$objectsY$archiverT$top † §U$nullÓ WNS.keysZNS.objectsV$class¢ €€¢€€€_0PTImageIOFormatDocumentViewingVisibleRectInfoKey_)PTImageIOFormatDocumentViewingZoomInfoKey_{{-240, -197}, {735, 649}}"? ÒZ$classnameX$classes\NSDictionary¢XNSObject_NSKeyedArchiverÑ Troot€ # - 2 7 ? E L T _ f i k m p r t v © Õ ò ÷ ü );>C ! E„+cˆPTImageIOFormatDocumentLayersLinkingInfoKeybplist00Ô&'X$versionX$objectsY$archiverT$top † ¨"U$nullÓ WNS.keysZNS.objectsV$class¢ €€¢€€€_;926AF512-89B2-4DDE-8416-F566A340952B-33484-00049CB677529F22_;1694E7C5-C84A-4D7F-914A-B167154D2BB1-33484-00049CC05957A93EÒ €ÒZ$classnameX$classes^NSMutableArray£WNSArrayXNSObjectÒ €Ò#$_NSMutableDictionary£#%\NSDictionary_NSKeyedArchiverÑ()Troot€ # - 2 7 @ F M U ` g j l n q s u w µ ó ø ù û #'/8=>@E[_l~† * ˆ J > Üé¶€J 4mPTImageIOFormatDocumentNumberOfComponentsInfoKey44 iPTImageIOFormatDocumentBitmapDataFormatInfoKey1YPTImageIOFormatDocumentSaveDateInfoKeyAÕV§ …pm‹PTImageIOFormatDocumentFileVersionSupportInfoKeybplist00Ô12X$versionX$objectsY$archiverT$top † ®$%&,-.U$nullÓ WNS.keysZNS.objectsV$class¥ €€€€€¥ €€€€€€ _PTImageIOPlatformMacOS_%PTImageIOFormatDocumentVersionInfoKey_-PTImageIOFormatDocumentSavedOnPlatformInfoKey_1PTImageIOFormatDocumentSavedWithAppVersionInfoKey_5PTImageIOFormatDocumentMinimumSupportedVersionInfoKeyÓ !#¡ €¡"€ € _7PTImageIOFormatDocumentRequiresMinimumAppVersionInfoKeyU3.1.1Ò'()*Z$classnameX$classes\NSDictionary¢)+XNSObjectS1.4S3.2Ò'(/0_NSMutableDictionary£/)+_NSKeyedArchiverÑ34Troot€ # - 2 7 F L S [ f m s u w y { } ƒ … ‡ ‰ ‹ ¨ Ð 4lsuwy{}·½ÂÍÖãæïó÷ü(+0 5 2/ Q!PTImageIOFormatDocumentSizeInfoKey{512, 512}Œ. u—xPTImageIOFormatDocumentOriginalExifDictionaryInfoKeybplist00Ô®¯X$versionX$objectsY$archiverT$top † ¯@-./0123456789:; €€?€V{TIFF}V{Exif}_*kCGImageDestinationLossyCompressionQuality[PixelHeightV{IPTC}XHasAlphaV{JFIF}ZPixelWidth[ProfileNameXDPIWidthU{PNG}YDPIHeightZColorModel[OrientationUDepthÓ =E,§>?@ABD€€€€€€€§*GHIJ*L€€€€€€€€^ResolutionUnitXSoftware[CompressionXDateTime[XResolution[YResolution^Pixelmator 3.2_2014:09:11 09:09:46"B "B Ò[\]^Z$classnameX$classes_NSMutableDictionary£]_`\NSDictionaryXNSObjectÓ bf,£cde€ €!€"£gg*€#€#€€_PixelXDimension_PixelYDimensionZColorSpace "?€ "D Ó rv,£stu€'€(€)£wx*€*€,€€_OriginatingProgram^ProgramVersion_ImageOrientationÒ€WNS.dataJPixelmator€+Ò[\ƒ„]NSMutableData£ƒ…`VNSDataÒ‡C3.2€+ Ó ‹,¤ŒŽ€/€0€1€2¤‘’“*€3€4€5€€XYDensity]IsProgressiveXXDensity[DensityUnit"B "B "D _sRGB IEC61966-2.1"B Ó ¡¤,¢¢£€:€;¢¥¥€<€<€_XPixelsPerMeter_YPixelsPerMeter"B SRGB_NSKeyedArchiverѰ±Troot€ # - 2 7 z € ‡ š ¡ ³ µ · ¹ » ½ ¿ Á Ã Å Ç É Ë Í Ï Ñ ã å ç é ë í ï ñ ó õ ÷ ù û ý ÿ >JQZalx‡‘œ¨®µ½¿ÁÃÅÇÉËÓÕ×ÙÛÝßáãòû(*9;QV[`ktŠŽ›¤«¯±³µ¹»½¿ÁÓåðóøý />QV^ikp~‚‰Ž’”•œ¡£¥§©®°²´¶¸ÁÏØäéêïô "$6HKPTVhkp ² r…?UŠ:PTImageIOFormatDocumentGuidesInfoKeybplist00ÔBCX$versionX$objectsY$archiverT$top † ¯%&'()*+,-./0125<=>U$nullÓ $WNS.keysZNS.objectsV$class« €€€€€€€€ € €€«!€ €€€ € € €€€€€ €ZsnapToGrid\snapToLayers[guidesArray]rulersVisible\guidesLocked\guidesHidden_rulersMeasurementUnits\snapToGuides\rulersOffset\snapToBounds[gridVisible Ò 34 €Ò6789Z$classnameX$classes^NSMutableArray£8:;WNSArrayXNSObject V{0, 0}Ò67?@_NSMutableDictionary£?A;\NSDictionary_NSKeyedArchiverÑDETroot€ # - 2 7 N T [ c n u ƒ … ‡ ‰ ‹ ‘ “ • — £ ¥ § © « ¯ ± ³ µ · ¹ » Æ Ó ß í ú -:GSTUZ[]bmv…‰‘šœ£¨¾ÂÏáäé F ë ƒ ƒ ˜zi±PTImageIOFormatDocumentColorsyncProfileInfoKey HLino mntrRGB XYZ Î 1 acspMSFT IEC sRGB öÖ Ó-HP cprt P 3desc „ lwtpt ð bkpt rXYZ gXYZ , bXYZ @ dmnd T pdmdd Ä ˆvued L †view Ô $lumi ø meas $tech 0 rTRC <