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
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/install-matlab.html 0000644 0001750 0001750 00000004554 12420040400 016006 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). Let VLFEATROOT denote
this directory. VLFeat must be added to MATLAB search path by running
the vl_setup command found in
the VLFEATROOT/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 demo
vl_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 running vl_setup demo.
vlfeat/docsrc/compiling.html 0000644 0001750 0001750 00000020152 12570775230 015101 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 type make:
$ 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 use make
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 to make as
follows. First, determine MATLAB's root directory by running a MATLAB
session and issuing the matlabroot
command. Let MATLABROOT denote the returned path
(e.g. /Applications/MATLAB_R2009b.app/). The mex
script is usually located in MALTABROOT/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
setting ARCH=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 the mex
script before attempting this. Th fix the bug, edit the
MATLABROOT/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.
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
%tableofcontents;
VLFeat 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 use vl_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 assignments A. By means of the cluster
centers
C we can project more data on the same clusters
datat = 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 are k=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 when K=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
vlfeat/docsrc/tutorials/kdtree.html 0000644 0001750 0001750 00000013625 12570775230 016433 0 ustar dima dima
%tableofcontents;
VLFeat 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
points X. Given a query point Q, the
function vl_kdtreequery returns its nearest neighbor
in X:
Q = rand(2, 1) ;
[index, distance] = vl_kdtreequery(kdforest, X, Q) ;
Here index stores the index of the column
of X that is closest to the point Q.
distance is the squared euclidean distance between X(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 of
vl_kdtreebuild).
kd-tree partitions of a uniform set of data points, using
the mean (left image) and the median (right image) thresholding
options of vl_kdtreebuild. On the bottom right corner
a query point is marked along with the ten closest neighbors as
found by vl_kdtreequery. Figure generated
by vl_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 point Q.
For instance:
[index, distance] = vl_kdtreequery(kdtree, X, Q, 'NumNeighbors', 10) ;
returns the closest 10 neighbors to Q
in X and their distances, stored along the columns of
index and distance.
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 in X.
Finding the 10 approximated nearest neighbors for increasing
values of the MaxComparisons parameter. Note that at
most MaxComparisons neighbors can be returned (if more
are requested, they are ignored). Figure generated
by vl_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 of
vl_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 instance
kdtree = vl_kdtreebuild(X, 'NumTrees', 4) ;
[index, distance] = vl_kdtreequery(kdtree, X, Q) ;
constructs four trees and queries them.
The parameter NumTrees
tells vl_kdtreebuild to construct a number of
randomized kd-trees. Figure generated
by vl_demo_kdtree_forest.
vlfeat/docsrc/tutorials/covdet.html 0000644 0001750 0001750 00000033140 12570775230 016433 0 ustar dima dima
%tableofcontents;
This 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 features
hold on ;
vl_plotframe(frames) ;
which results in the image
The default features detected by vl_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, setting PatchRelativeExtent 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 by
PatchRelativeExtent/PatchResolution).
Extracting higher resolution patches may be needed for larger extent
and smaller smoothing. A good setting for this parameter may be
PatchRelativeExtent/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).
vlfeat/docsrc/tutorials/kmeans.html 0000644 0001750 0001750 00000012235 12570775230 016427 0 ustar dima dima
%tableofcontents;
This 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
vector assignments 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 of MaxNumComparison, 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 using
vl_demo_kmeans_ann_speed.
vlfeat/docsrc/tutorials/utils.html 0000644 0001750 0001750 00000004057 12570775230 016314 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 and vl_imarraysc arrange and visualize multiple
images in a grid
vl_imsc scales the image range;
vl_tightsubplot is similar to built-in
subplot, but produces narrower margins.
vl_cf makes a copy of a figure.
vl_rodr and vl_irodr compute the Rodrigues' formula and
its inverse
vl_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 with vl_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/aib.html 0000644 0001750 0001750 00000003702 12570775230 015703 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.
vlfeat/docsrc/tutorials/mser.html 0000644 0001750 0001750 00000021066 12570775230 016121 0 ustar dima dima
%tableofcontents;
Maximally 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 image I. 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
MSER
Extracting MSERs
Each MSERs can be identified uniquely by (at least) one of its
pixels x, as the connected component of the level set at
level I(x) which contains x. 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 image
pfx = 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 the vl_mser code assumes that the row index
is the first index, but the normal image convention assumes that this is the
x (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-in contour, which draws the contour lines
of a function. We start by
M = 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 use M
and contour 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 region
R which is stable at R(+Δ).
The stability of an extremal region R is the inverse
of the relative area variation of the region R when the
intensity level is increased by Δ. Formally, the
variation is defined as:
|R(+Δ) - R|
-----------
|R|
where |R| denotes the area of the extremal region
R, R(+Δ) is the extremal region
+Δ levels up which contains R 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 and DarkOnBright 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 the x
and y 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
and image.seed contain the feature frames and seeds in
ASCII format as generated by the command line utility. Then
r_ = 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 and r_ and frames f
and f_.
vlfeat/docsrc/tutorials/encode.html 0000644 0001750 0001750 00000010575 12570775755 016427 0 ustar dima dima
%tableofcontents;
This 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 the vl_fisher function using the
output of the vl_gmm function:
encoding = vl_fisher(datatoBeEncoded, means, covariances, priors);
The encoding vector is the Fisher vector
representation of the data dataToBeEncoded.
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
the vl_vlad function to compute the encoding. Differently
from vl_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 matrix dataToBeEncoded. 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.
vlfeat/docsrc/tutorials/svm.html 0000644 0001750 0001750 00000012652 12570775230 015761 0 ustar dima dima
%tableofcontents;
VLFeat 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/plots-rank.html 0000644 0001750 0001750 00000021756 12570775230 017253 0 ustar dima dima
This tutorial illustrates the use of the functions
vl_roc,
vl_det, and
vl_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
score scores. 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 than k (where
ranks are assigned by decreasing scores). tnr(k) is
instead the percentage of negative samples that have rank larger
than k. Therefore, if one classifies the samples with
rank smaller or equal than k to be positive and the rest
to be negative, tpr(k) and tnr(k) are
repsectively the probability that a positive/negative sample is
classified correctly.
Moving from rank k to rank k+1, if the
sample of rank k+1 is positive then tpr
increases; otherwise tnr 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
the numNegatives and numPositives
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
in labels and scores 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 than k-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 than k-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, then recall(3) is 1/5.
Moving from rank k to rank k+1, if the
sample of rank k+1 is positive then
both precision and recall increase;
otherwise precision decreases and recall
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 as info.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.
vlfeat/docsrc/tutorials/hikm.html 0000644 0001750 0001750 00000007325 12570775230 016105 0 ustar dima dima
%tableofcontents;
VLFeat 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 least
nleaves nodes, creating a tree with depth =
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 field
sub 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 field
sub 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 when K=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/slic.html 0000644 0001750 0001750 00000002702 12570775230 016101 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 segmented
In 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 and
regularizer one obtains the segmentations:
SLIC segmentations regionSize
spaning the values 10,30, and
regularizer 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) ;
vlfeat/docsrc/tutorials/hog.html 0000644 0001750 0001750 00000013147 12570775230 015731 0 ustar dima dima
%tableofcontents;
The 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 the
numOrientations 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 for numOrientations
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 for numOrientations equals to
four, and soft orientation assigments.
vlfeat/docsrc/tutorials/frame.html 0000644 0001750 0001750 00000021011 12570775230 016233 0 ustar dima dima
%tableofcontents;
This 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 in vl_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
by vl_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
by vl_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 fragment
f = [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 by vl_demo_frame.
Note that, when features extracted by a detector such
as vl_covdet or vl_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 calling vl_frame2oell; note that the
orientation is upright. Figure generated
by vl_demo_frame.
vlfeat/docsrc/tutorials/liop.html 0000644 0001750 0001750 00000003361 12570775230 016114 0 ustar dima dima
%tableofcontents;
This tutorial shows how to extract Local
Intensity Order Pattern (LIOP) deascriptors using VLFeat. LIOP is
implemented in the vl_liop as well as
in vl_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
the vl_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
into vl_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
example
descr = vl_covdet(patch,'IntensityThreshold', 0.1) ;
set this threshold to 0.1.
vlfeat/docsrc/tutorials/gmm.html 0000644 0001750 0001750 00000012730 12570775230 015731 0 ustar dima dima
%tableofcontents;
This 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
and priors are respectively the means $\mu_k$, diagonal
covariance matrices $\Sigma_k$, and prior probabilities $\pi_k$ of
the numClusters 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 by vl_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
and vl_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.
vlfeat/docsrc/tutorials/quickshift.html 0000644 0001750 0001750 00000007352 12570775230 017327 0 ustar dima dima
%tableofcontents;
Quick 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 segment
As 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, and maxdist is the maximum distance between points in the feature space that may be linked if the density is increased.
The effect of maxdist on the superpixelization. As we increase maxdist, 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 every dist < 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 multiple maxdist thresholds on a single image. Here, boundaries are colored by the largest maxdist where the boundary is preserved.
vlfeat/docsrc/tutorials/imdisttf.html 0000644 0001750 0001750 00000006241 12570775230 016774 0 ustar dima dima
The distance transform of an image image is defined
as
dt(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 by vl_demo_imdisttf.
The edge map is preprocessed to assign value -inf to
the pixels that do not contain an edge element and o 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 chooses alpha=beta=1 and v0=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 distance sqrt(distanceTransform) to the closest
edge element (left) and arrows connecting pixels to their closest
edge element (right). Figure generated
by vl_demo_imdisttf.
References
[1] P. F. Felzenszwalb and
D. P. Huttenlocher. Distance transforms of sampled
functions. Technical report, Cornell University, 2004.
vlfeat/docsrc/using-gcc.html 0000644 0001750 0001750 00000001753 12420040400 014757 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 replace a64 with your architecture
(a64 for 64 bit linux, glx for 32 bit linux).
vlfeat/docsrc/vlfeat-website-preproc.xml 0000644 0001750 0001750 00000001772 12570775230 017354 0 ustar dima dima
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
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 (here vlfeat-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 add vl.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-website.xml 0000644 0001750 0001750 00000002512 12570775230 015675 0 ustar dima dima
These man pages describe VLFeat command line utilities.
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:;\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 <