Pierluigi Taddei

Eternal incomplete home page

  • Increase font size
  • Default font size
  • Decrease font size
pigei.com

WildMagic5 and CMake

Say that you want to use the GeometricTools libraries (a.k.a WildMagic5 ) in your project. Here are the steps to setup yourVisual Studio environment in case you want to link these libraries dynamically (dlls) and in case you are using CMake to build your project.

GeometricTools installation (with dynamic libraries)

  1. Download the current version of WildMagic5 and unzip the package in a convenient folder (from now on [wm5folder] )
  2. WildMagic5 comes with a set of Visual Studio solution ready to be compiled. Open the one related to your Visual Studio version (say WildMagic5_V90.sln)
  3. Here you have the option to compile four different configuration (depending if you need Debug/Release or Opengl/DirectX). Unfortunately from here you can only compile static libraries.
    1. In order to build the dlls you will need to open the Visual Studio projects one after the other and compile the following configuration: DebugDLL, ReleaseDLL
    2. After that you will find all the .lib and .dll in the [wm5folder]/SDK/Library/ReleaseDLL and [wm5folder]/SDK/Library/DebugDLL
  4. To complete the installation of WM5 add the followoing environment variable to your system: WM5_DIR = [wm5folder]/SDK
  5. Add the following folder to your system path:  [wm5folder]/SDK/Library/ReleaseDLL and [wm5folder]/SDK/Library/DebugDLL

Linking your project to the dynamic libraries

  1. Copy the following script either in your project folder or in the CMake share folder. This file will be used to setup the variables related to GeometricTools
  1. For all projects that will use WildMagic5 add the following line in the related cmake scripts:

    FIND_PACKAGE(Wm5 REQUIRED)
    INCLUDE_DIRECTORIES(${WM5_INCLUDE_DIR})

    [...]

    TARGET_LINK_LIBRARIES( [...] ${WM5_LIBRARIES}) #Add Wm5 libraries to your target project (in this case a dll)
  2. In case that you do not want to link all Wm5 libraries you may setup the following variable BEFORE calling FIND_PACKAGE:
    SET(WM5_FIND_REQUIRED_COMPONENTS WM5_WM5CORE WM5_WM5MATHEMATICS ) #this will only load core and mathematics fro instance

 

 

Hyperview in Vigevano

The 11th of September the L3 HyperView application I have developed with Alessandro Giusti will be shown in the exibit "Il Laboratorio di Leonardo - I codici, le macchine, i disegni "

HyperView is a Java application that allows one to display very large images using a texture tiles cache approach, very much similar to what happens in google maps.

For this event I added new functionality: the new version of the program allows to add media content to the image, such as MP3s and descriptive images at different levels. It will be deployed on big touchscreen monitors in order to improve the user interaction with the media.

If you need more information on the technology please contact me

 

Planar Motion Estimation

I will present a work at OMNIVIS 2008 in Marseille, France during the ECCV 2008 conference.

odometry.png

Abstract

Generic camera odometry can be performed using two images of the same plane, such as the ground plane even in the case of non central cameras. It is possible to recover both the angle and rotation center describing a generic planar motion on the ground plane if the center is visible in both images. We present an algorithm to recover these two parameters from an initial set of correspondences and, furthermore, to estimate the motion flow related to any point on the ground plane. In this situation the motion flows are given by a set of "concentric" closed curves around the rotation center. By considering two subsequent ground plane motions and their related motion flows, we show that it is possible to perform a rectification of the plane up to a scale factor. We provide experimental results which validate our approach.

 

Conic intersection

I made some small bug fixes to the conic intersection package. Thanks to Dany for pointing the bug out. The matlab code that you can download here can be used to detect the (up to) four intersections of two conics. The usage is quite straightforward but anyway, here is an example:

%%the homogeneous representation of a conic is a matrix 
%% m = [A C D; C B E; D E F] that represents the equation 
%% A x^2 + B y^2 + 2C xy + 2D x + 2Ey + F = 0


%a circle centered in the origin

E1 = [1 0 0; 0 1 0; 0 0 -3] 

%an ellipse centered in the origin

E2 = [1 0 0; 0 3 0; 0 0 -6] 

%get the four homogeneous intersections
P = intersectConics(E1, E2) 
%plot the normalized points
plot(P(1,:) ./ P(3,:) , P(2,:) ./ P(3,:), 'ro');

Algorithm description

The solutions to a two second degree equations system in two variables may be seen as the coordinates of the intersections of two generic conic section. In particular two conics may possess none, two, four possibly coincident intersection points. The best method to locate these solutions is to exploit the homogeneous matrix representation of conic sections, i.e. a 3x3 symmetric matrix which depends on six parameters.

The procedure to locate the intersection points follows these steps:

  • given the two conics C1 and C2 consider the pencil of conics given by their linear combination ?C1 + ?C2
  • identify the homogeneous parameters (?,?) which corresponds to the degenerate conic of the pencil. This can be done by imposing that det(?C1 + ?C2) = 0, which turns out to be the solution to a third degree equation.
  • given the degenerate cone C0, identify the two, possibly coincident, lines constituting it
  • intersects each identified line with one of the two original conic; this step can be done efficiently using the dual conic representation of C0
  • the points of intersection will represent the solution to the initial equation system

Matlab implementation

In the library you will find a couple of matlab function which implements the above steps to intersect two conics. In particular the main functions are:

  • intersectConics : this is the main function to perform the intersection
  • decomposeDegenerateConic: this function allow to split a degenerate conic into two lines
  • intersecLineConic: this function recover the, possibly two, points of intersection of a line and a conic

If you have any comments please refer to me by email!

 

Paper like surfaces

I have presented at NORDIA Workshop in Anchorage (Alaska) a work done in conjuction with Adrien Bartoli. Here is the related paper

Here is the presentation of the work:

 

Catadioptric Cameras

The following papers have been presented the 20th of October at Omnivis 2007 in conjunction with the ICCV 2007 conference in Rio de Janeiro. I will add a brief description of the two works as time will permit.

 

L3 Hyperview

Alessandro Giusti and me developed the Java+OpenGL powered viewer technology behind L3 HyperView.  L3 HyperView is an userfriendly viewer for gigapixel-class images with smooth pan, zoom, rotation and innovative input interfaces.

Leonardo3 HyperView premiered on 12-20 May 2007 at Biblioteca Reale, Torino during the "Codex on flight" exposition, where very high resolution images were displayed on Full High-Definition HDTV screens.

Learn more at L3 homepage and the exposition page (includes photos, press release and video of national TV coverage by RAI3 TG3 Leonardo).

 

Periodic B-spline

closedspline.png In my last work I have extensively used multivariate b spline to perform data interpolation ad to exploit a parametric model for image mappings. In particular my work required periodic and continuous b-spline. This version of a b-spline requires two less parameters for each dimension since we imposes C2continuity on the period boundary. 
In this article I present a rather smart and compact implementation for R -> R2 periodic b-spline with evenly spaced knots using cubic spline as atomic support (i.e each b-spline covers 5 subsequent knots).

You may use this function as in the following  example

a = linspace(0,2*pi, 12); a = a(1:end-1);
p = [cos(a); 2*sin(a)]

cs = closedSpline(a, p, 8); %creates the periodic spline
y  = cs.eval( linspace(0,2*pi,100) ); %evaluate the spline in 100 points

plot(p(1,:),p(2,:), 'b.');
plot(y(1,:), y(2,:), '-r');

I am going to post shortly the link to the two required function and possibly to extends this post to add more details!

Here is the matlab function used to create a closed 2D spline.

 % Compute a 2D closed spline 
%              - Pierluigi Taddei ( This e-mail address is being protected from spambots. You need JavaScript enabled to view it )
%
% Usage:  sp =  closedSpline(a, p, n)
%              
% Arguments:
%          a - domain values (i.e linspace(0, 2*pi, k) )
%          p - image values on the plane (the value of the spline in a)
%          n - number of spline knots (should be less than number of
%          values)
% 27.03.2009 : Created

function ps = closedSpline(a, p, n)

if(n > length(a))
n = length(a);
end

ps = struct();

%atomic spline element

knots = linspace(0,2*pi, n+1); knots = knots(1:end-1);
baseSpline = spmak(knots(1:5),1);


%%move values to a single bspline equivalent
Afull = repmat(a', 1,length(knots)) - repmat(knots, length(a),1);
Afull2 = mod(Afull, 2*pi); %remove periodicity

A = fnval(baseSpline, Afull2); %evaluate bspline in all points
%least square minimization
ku = A \ p(1,:)';
kv = A \ p(2,:)';

%file the structure
ps.knots = knots;
ps.baseSpline = baseSpline;
ps.paramU = ku;
ps.paramV = kv;

%add the evaluation method to the spline itself

ps.eval = @(x)csval(ps,x);
end

Given a set of initial points the function creates a linear sistem wich will be solved in order to detect the  best parameter value in the least square sense.

Once the parameters are known you can call the csval function to evaluate the spline in any point of the domain (thanks to its periodicity). You can both call this function directly or use an object oriented call style on the spline structure.

% Evaluate a closed 2D spline for values a
%              - Pierluigi Taddei ( This e-mail address is being protected from spambots. You need JavaScript enabled to view it )
%
% Usage:  y = csval(cs,a)
%               
%          
% Arguments:
%          cs - the closed spline
%          a - domain values vector
% 27.03.2009 : Created

function y = csval(cs,a)
k = cs.knots;

aVal = repmat(a, length(k),1) - repmat(k', 1, length(a));
aVal2 = mod(aVal, 2*pi);
bVal = fnval(cs.baseSpline, aVal2);

u = sum( bVal .* repmat(cs.paramU, 1,length(a)),1 );
v = sum( bVal .* repmat(cs.paramV, 1,length(a)),1 );

y = [u;v];
end
 

Fuji Mountain

Here is a good example of pixel art.

While the broom and the bride were on their return flight from Japan, we organized a special present on one of their apartment walls. The drawing is a simple 43 x 30 image where each pixel is represented by a single 76 mm x 76 mm post-it.

To generate the image I have simply resampled a vectoral image down to the required resolution using nearest neighbor. The apartment floor was then completely filled by 11.000 plastic glasses full of water (which actually took all of the time). Enjoy the video!

A special thanks to all the partecipants! (Paola, Elena, Danja, Annamaria, Celeste, Gladis, Martina, Muriel, Italo, Kuda, Giampaolo, Davide, Andrea, myself and my broken leg)

 

MVC (Model View Controller) by example

In this article I will show, using a straightforward example, how to implement and exploit the MVC framework (Model View Controller) in order to completely decouple the presentation from the logic of (possibly) any application. If you have any comment or doubt, please feel free to contact me.

  • testMVC.jar: this package contains the Java imlpementation described in the article

Thus, let's start from the following demo application: "A system which allow the user to start generic jobs and to track their progress. In this dummy application jobs do not  perform any operations apart waiting a couple of seconds to complete. The user has the possibility to:

  • see the current progress of completion of all jobs started
  • launch another job that will start immediately
  • close the application

For simplicity jobs do not require any input parameters and  the time required to complete is randomly calculated at creation time. Each specified time interval the job progress is incremented until it completes."

The model

The model part of our system should represent the state of the application in any given instant. It should provide method to modify and read the states but not the logic on how to do that. Moreover it do not possess any instruction on how to display its variables.
Thus the model is independent from the user interface used and from the logic that modify the states. We may state that it is represented by the nodes of a finite state automata.
In my running example the system model is represented by a class called Model (surprising, isn't it?)

/**The Model represents the state of the system in the current instant*/
public class Model [...] {

[...]

/**The model is represented by a set of working jobs*/
private ArrayList<Job> array;

public Model(){
array = new ArrayList<Job>();
[...]
}

/**add the given job to the state and notify all listeners*/
public void addJob(Job j) {
array.add(j);       
[...]
}

public Collection<Job> getJobs() {
return array;
}
}

The class just contains an array of object Job and some methods to add and retrieve these instances. The class Job itself is quite simple:

public class Job extends javax.swing.DefaultBoundedRangeModel{

/**used to count the instances of job generated */
private static int counter = 0;
private static final long serialVersionUID = 1L;

/**instance number of this job*/
private int idx;

public Job(){
super(0,0, 0, (int)Math.rint(Math.random()*1000));
idx = ++counter;
}

/** @return true if the current value is equal to the maximum value*/
public boolean isCompleted() {
return super.getValue() >= super.getMaximum();
}

public String toString(){
return "job " + idx + "(" + getValue() + "/" + getMaximum() + ")";
}
}

I've extended a model class taken directly from the Swing library. This is just a shortcut to write less code, since that model (BoundedRangeModel)  fits perfectly my needs. It is a class used to store the state of n object which have a minimum m,  a maximum M value and a current value V such as m <= V <= M. Thus it correctly represent a Job as it is described by our specification.

Adding a model listener

In order to react to model state changes I will adopt the observer/observable pattern. In particular the model will represent the observable object and all interfaces will represent its observers. n particular each view will extends the following interface:

/**Listener to event thrown by the Model*/
public interface ModelListener {

/** notification of a newly added job j*/
public void notifyJobAdd(Job j);

/** notification of the completion of job j*/
public void notifyJobCompleted(Job j);
}

The two event that we are going to observe are the add of a newly created job and the completion of a previous job. 
When these events happen, the model needs to notify all the registered observers. Thus the model need to expose a methodaddListener() which is used to register a new observer to it. Moreover in order to notify of a job completion the model need to observe each working job: the model itself is the observer of the observable job.
The complete Model class is represented by the following (where in addition you will find the code to manage the listeners):

/**The Model represents the state of the system in the current instant*/
public class Model implements ChangeListener {

/**Set of listeners which are registered to event thrown by this model*/
HashSet<ModelListener> listeners = null;

/**The model is represented by a set of working jobs*/
private ArrayList<Job> array;


public Model(){
array = new ArrayList<Job>();
listeners = new HashSet<ModelListener>();
}

/**add a listener to event thrown by this class*/
public void addListener(ModelListener l){        
listeners.add(l);
}

/**add the given job to the state and notify all listeners*/
public void addJob(Job j) {
array.add(j);
j.addChangeListener(this); //this model listens to changes in each job state

for(ModelListener l : listeners) l.notifyJobAdd(j);
}

/**notification of a change in one of the model jobs: the notification is forwarded to the model listener*/
public void stateChanged(ChangeEvent e) {
Job j = (Job)e.getSource(); //the job which threw the event
if (j.isCompleted()) {
for(ModelListener l : listeners) l.notifyJobCompleted(j);
}
}

public Collection<Job> getJobs() {
return array;
}
}

The controller

The controller will represents the logic that modify the state of the system. It should provide method to perform actions required by the user, it should check the validity of such actions and perform any transitions from a state to the other. It represents the arcs of the finite state automata.

In our example the controller simply exposes a method to add a new job (addJobAction()). The jobs update, instead, is implemented using a concurrent thread for each working job. When a job is created and added to the model, a JobThread is associated to it; this thread simply keeps updating at regular intervals the job progress until it completes.

public class Controller {

Model model;

public Controller(Model m){
this.model = m;
}

/**The controller is able to create a new job via this action*/
public void createJobAction(){
//create a new job
Job j = new Job();
//add it to the model (this will throw a notification to the UIs)
model.addJob(j);

//start a thread to update the job concurrently
new JobThread(j).start();
}

/** A thread used to update each job concurrently to the other application threads */
private class JobThread extends Thread{

private Job j; //the job to manage
public JobThread(Job j){
this.j = j;
}

public void run(){
//keep incrementing the job progress at each interation
while(!j.isCompleted()){
try {
int ct = j.getValue();
j.setValue(ct+1);
synchronized(this) {
wait(20); //wait some times from an update to the other
}
} catch (InterruptedException e) {
//the thread has been woken up..
}
}
}
}
}

The view

The view represents a module which is able to read the current state and display it to the user. Moreover it receives input from the user and transforms them into action which are transmitted to the controller.
In my example I've implemented two different view: a textual user interface, which exploits System.out and System.in to interact with the user, and a graphical user interface, which uses Swing widgets to do the same. notice that both views requires to implement the ModelListener interface in order to react to model changes, and both requires the controller in order to perform actions.

Textual user interface

public class Tui implements ModelListener{

private Model model;
private Controller controller;

public Tui(Model m, Controller c){
this.model = m;
this.controller = c;
}

/**Shows the menu on the console and WAIT for an input from the user. The method stops by closing the application*/
public void display(){
Scanner s = new Scanner(System.in);

boolean  keepWorking = true;
while (keepWorking){
System.out.println("_______________________________________________________________________");
System.out.println("what do you need dude?");
System.out.println("1: \trefresh system state");
System.out.println("2: \tadd a job");
System.out.println("3: \tget out of here!");
System.out.println("_______________________________________________________________________");

int x  = s.nextInt(); //this is a blocking method...
System.out.println();
System.out.println();

switch (x){ //check the user requests
case 1: //display the current status of the model
displayJobs();
break;
case 2: //create a new job
controller.createJobAction();
break;
case 3: //get out of the program
keepWorking = false;
System.exit(0);
break;
}

}

}

/**displays the status of the system in this istant*/
private void displayJobs() {
Collection<Job> c = model.getJobs();

for(Job j : c){ //for each job output a descritpion line
System.out.print(j + "\t");
int x = 100*j.getValue() /j.getMaximum();
String token = (x == 100)? "#" : "-";
for (int i=0; i < x; i++) System.out.print(token);
System.out.println();
}
}

public void notifyJobAdd(Job j) {
System.out.println(j + " was succesfully added and started");
displayJobs();
}

public void notifyJobCompleted(Job j) {
System.out.println(j + " has completed");        
}

}

Graphical user interface

public class Gui extends JFrame implements ModelListener{

private static final long serialVersionUID = 1L;

private Controller controller;

/**Correspondence between each Job and its related progress bar*/
private HashMap<Job, JProgressBar> bars = new HashMap<Job, JProgressBar>();

public Gui(Model m, Controller c){
this.controller = c;
setGUI();
}

private void setGUI(){
//use a simple vertical box layout
BoxLayout bl = new BoxLayout(this.getContentPane(), BoxLayout.PAGE_AXIS);
this.getContentPane().setLayout(bl);

this.setMinimumSize(new Dimension(600,400));

JButton b = new JButton();
b.setAction(new AddAction());
b.setText("add job...");
b.setAlignmentX(0.5f);
this.add(b);

this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

/**Action thrown when the add button is pressed*/
private class AddAction extends AbstractAction{
private static final long serialVersionUID = 1L;

public void actionPerformed(ActionEvent e) {
controller.createJobAction();
}
}

/**notification from the model that a job has been added*/
public void notifyJobAdd(Job j) {
//create a new progress bar using j as the corresponent model
JProgressBar bar = new JProgressBar(j);

bar.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
bars.put(j, bar);

this.getContentPane().add(bar);

//revalidate the layout (there is a new item inserted)
this.validate();
this.pack();

}

/** displays in red the completed jobs*/
public void notifyJobCompleted(Job j) {
JProgressBar bar = bars.get(j);
bar.setForeground(Color.RED);
bar.repaint();

}

/**shows the window interface*/
public void display() {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
setLocationByPlatform(true);
setVisible(true);
}
});
}
}

Both views implements a display method which is used to start the user interaction. Notice, however, that:

  • in the textual interface, this method is blocking, since it keeps looping in order to show a menu after each user requests and then wait for a user keyboard input
  • in the graphical interface, this method is non blocking, since it put a display request to the EventThread (setVisible(true)) and returns immediately.

Putting everything all thogether

Let's now create an overall class to instantiate and connect the components:

 public static void main(String... argv){

//instantiate the model
Model m  = new Model(); 

//instantiate the controller which requires a model
Controller c = new Controller(m);

//instantiate the uis, which require model and controller
Tui t  = new Tui(m, c);
Gui g = new Gui(m, c);


//register the uis as listeners of the model
m.addListener(g);
m.addListener(t);


//perform the display
g.display();
t.display();

//end this thread
}

Notice in this code fragment that I have instantiated both a graphical user interface and a textual interface on the same model. The system still work perfectly allowing the user to control the state in two different ways at the same time!
The fragment is straightforward; at first I have instantiated a new model which is then fed to the controller, since it have to control it; then it's the turn of the two interfaces which are instantiated using both the controller and the model as input; finally I've performed the listener registration on the model of both interfaces in order to allow these to "listen" for changes in the system state.

If you have any comment or doubt, please feel free to contact me

 

Contacts

 

Pierluigi Taddei

European Joint Research Centre
via Enrico Fermi, 2749
21027 Ispra

Italy

Email: pierluigi.taddei at gmail dot com

Phone: +39 3491566235

 

Who I Am

I am Pierluigi Taddei,

I work on 3D Reconstruction and Computer Vision since 2006, currently I am working as a Post Doc at the European Joint Research Centre (JRC) where I mainly deal with 3D reconstruction using laser scanners. I am also interested in other fields such as developing rich internet applications, computer graphic applications and geometric issues.

This site contains some articles related to my research and other activities I find useful to share. Unfortunately I am always running out of time, so this list will be eternally incomplete! Please contact me for any questions