you could subdivide your mesh more finely.

alternatively, you could do pixel warping instead, but that’s very slow.

you could subdivide your mesh more finely.

alternatively, you could do pixel warping instead, but that’s very slow.

I have done something like this. The basic process is to draw to an FBO and then map that FBO to a bezier shape in OpenGL. The bezier shape can then be warped to any size/shape you would like by editing individual points. I used this method to do a pretty complicated interactive wall on a curved screen, so it works pretty well.

Here is my post, or you could say journal entry :-), on how I did it: http://forum.openframeworks.cc/t/ofxfbo-texture-mapping--cylinder/4002/0 skip to the bottom to get the best code example.

Also, if you are using Alpha blending, you have to change the blending mode depending on if you are drawing to FBO, or mapping the texture to the bezier shape. see http://forum.openframeworks.cc/t/fbo-problems-with-alpha/1643/10 for details.

DISCLAIMER: I am very much a beginner at openGL, so the code is probably a bit sloppy, but works. (As we say in the South, Redneck programmin’: Don’t know why it works, but it does!)

*edit* Here is a screen shot of what can be accomplished. The pink circles are control points of the mesh.

blerg

i’ve been hitting my head against some bricks for 20hours now…

I keep getting duplicate symbol errors with this file:

ld: duplicate symbol homography::findHomography(ofPoint*, ofPoint*, float*)in /Users/elliot/openFrameworks 0.6/apps/elliots/bricks pc/build/bricks pc.build/Debug/bricks pc.build/Objects-normal/i386/testApp.o and /Users/elliot/openFrameworks 0.6/apps/elliots/bricks pc/build/bricks pc.build/Debug/bricks pc.build/Objects-normal/i386/main.o

collect2: ld returned 1 exit status

Command /Developer/usr/bin/g+±4.2 failed with exit code 1

I tried putting it in a class to see if that got around it. no luck. then i tried Xcode 4 (different compiler). Still same error.

brick wall. brick wall. smack…smack…

think i might try the opencv approach

the .h file you are using elliot needs a include gaurd, since it’s being included multiple times and you are getting a multiple definition error. Try adding:

#pragma once

at the top or,

#ifndef _H_HOMOGRAPHY

#define _H_HOMOGRAPHY

// content

#endif

at the top and bottom.

that prevents it from being included multiple times.

or just include it from one .cpp file.

hope that helps,

zach

have edited the original file to add the include guard

hi

i am using the matrix warping successfully.

i am noticing that my memory use slowly goes up.

would it make sense to do something like this at the end of the warping:

```
if(matrix != NULL) delete matrix;
if(src_mat != NULL) delete src_mat;
if(dst_mat != NULL) delete dst_mat;
if(translate != NULL) delete translate;
```

i am not too familiar with that so please excuse my lack of knowledge.

stephan.

Hi - thanks very much for sharing this code - just what I was looking for - here’s the simplest working example I could make - you click four times to place the corners for the destination of the image - see below.

I’ve been playing with projection surfaces and using this for a soft keystoning. What I’d really like now is to use the excellent work Kyle McDonald and others have been doing with Structured Light techniques to discover the matrix automatically - tricky I know!

Cheers,

Dave

```
---testApp.h
#ifndef _TEST_APP
#define _TEST_APP
#include "ofMain.h"
#include "ofxVectorMath.h"
class testApp : public ofBaseApp{
public:
void setup();
void draw();
void mousePressed(int x, int y, int button);
void findHomography(ofPoint src[4], ofPoint dst[4], float homography[16]);
void gaussian_elimination(float *input, int n);
ofImage image;
ofPoint des[4];
int clickCount;
};
#endif
---testApp.cpp
#include "testApp.h"
void testApp::setup(){
clickCount=0;
image.loadImage("image.jpg");
}
void testApp::draw(){
if(clickCount==4){
ofPoint src[]={ofPoint(0,0),ofPoint(image.width,0),ofPoint(image.width,image.height),ofPoint(0,image.height)};
GLfloat matrix[16];
findHomography(src,des,matrix);
glPushMatrix();
glMultMatrixf(matrix);
glPushMatrix();
image.draw(0,0);
glPopMatrix();
glPopMatrix();
}
}
void testApp::mousePressed(int x, int y, int button){
//click to place the destination of corners of the image - starting in the top left and moving clockwise
if(clickCount<4) {
des[clickCount]=ofPoint(x,y);
++clickCount;
}
}
void testApp::findHomography(ofPoint src[4], ofPoint dst[4], float homography[16]){
// arturo castro - 08/01/2010
//
// create the equation system to be solved
//
// from: Multiple View Geometry in Computer Vision 2ed
// Hartley R. and Zisserman A.
//
// x' = xH
// where H is the homography: a 3 by 3 matrix
// that transformed to inhomogeneous coordinates for each point
// gives the following equations for each point:
//
// x' * (h31*x + h32*y + h33) = h11*x + h12*y + h13
// y' * (h31*x + h32*y + h33) = h21*x + h22*y + h23
//
// as the homography is scale independent we can let h33 be 1 (indeed any of the terms)
// so for 4 points we have 8 equations for 8 terms to solve: h11 - h32
// after ordering the terms it gives the following matrix
// that can be solved with gaussian elimination:
float P[8][9]={
{-src[0].x, -src[0].y, -1, 0, 0, 0, src[0].x*dst[0].x, src[0].y*dst[0].x, -dst[0].x }, // h11
{ 0, 0, 0, -src[0].x, -src[0].y, -1, src[0].x*dst[0].y, src[0].y*dst[0].y, -dst[0].y }, // h12
{-src[1].x, -src[1].y, -1, 0, 0, 0, src[1].x*dst[1].x, src[1].y*dst[1].x, -dst[1].x }, // h13
{ 0, 0, 0, -src[1].x, -src[1].y, -1, src[1].x*dst[1].y, src[1].y*dst[1].y, -dst[1].y }, // h21
{-src[2].x, -src[2].y, -1, 0, 0, 0, src[2].x*dst[2].x, src[2].y*dst[2].x, -dst[2].x }, // h22
{ 0, 0, 0, -src[2].x, -src[2].y, -1, src[2].x*dst[2].y, src[2].y*dst[2].y, -dst[2].y }, // h23
{-src[3].x, -src[3].y, -1, 0, 0, 0, src[3].x*dst[3].x, src[3].y*dst[3].x, -dst[3].x }, // h31
{ 0, 0, 0, -src[3].x, -src[3].y, -1, src[3].x*dst[3].y, src[3].y*dst[3].y, -dst[3].y }, // h32
};
gaussian_elimination(&P[0][0],9);
// gaussian elimination gives the results of the equation system
// in the last column of the original matrix.
// opengl needs the transposed 4x4 matrix:
float aux_H[]={ P[0][8],P[3][8],0,P[6][8], // h11 h21 0 h31
P[1][8],P[4][8],0,P[7][8], // h12 h22 0 h32
0 , 0,0,0, // 0 0 0 0
P[2][8],P[5][8],0,1}; // h13 h23 0 h33
for(int i=0;i<16;i++) homography[i] = aux_H[i];
}
void testApp::gaussian_elimination(float *input, int n){
// arturo castro - 08/01/2010
//
// ported to c from pseudocode in
// [http://en.wikipedia.org/wiki/Gaussian-elimination](http://en.wikipedia.org/wiki/Gaussian-elimination)
float * A = input;
int i = 0;
int j = 0;
int m = n-1;
while (i < m && j < n){
// Find pivot in column j, starting in row i:
int maxi = i;
for(int k = i+1; k<m; k++){
if(fabs(A[k*n+j]) > fabs(A[maxi*n+j])){
maxi = k;
}
}
if (A[maxi*n+j] != 0){
//swap rows i and maxi, but do not change the value of i
if(i!=maxi)
for(int k=0;k<n;k++){
float aux = A[i*n+k];
A[i*n+k]=A[maxi*n+k];
A[maxi*n+k]=aux;
}
//Now A[i,j] will contain the old value of A[maxi,j].
//divide each entry in row i by A[i,j]
float A_ij=A[i*n+j];
for(int k=0;k<n;k++){
A[i*n+k]/=A_ij;
}
//Now A[i,j] will have the value 1.
for(int u = i+1; u< m; u++){
//subtract A[u,j] * row i from row u
float A_uj = A[u*n+j];
for(int k=0;k<n;k++){
A[u*n+k]-=A_uj*A[i*n+k];
}
//Now A[u,j] will be 0, since A[u,j] - A[i,j] * A[u,j] = A[u,j] - 1 * A[u,j] = 0.
}
i++;
}
j++;
}
//back substitution
for(int i=m-2;i>=0;i--){
for(int j=i+1;j<n-1;j++){
A[i*n+m]-=A[i*n+j]*A[j*n+m];
//A[i*n+j]=0;
}
}
}
```

1 Like

@zach

seems so simple. i cant think why that didn’t cross my mind.

i was (as may be obvious from the above wording) a bit paniced at the time and was starting to overlook things a little…

i went for cv in the end as it was only 1 matrix that needed calculating

I find homography to be such a useful feature (when in vvvv, i’m using it in almost every project), that i’d put a vote in for moving this into ofxVectorMath or something else that comes with oF.

again thanks for the hint

will try this out (with the guarded code) when xcode finishes reinstalling

(upgraded iPad, didn’t know i now have to upgrade xcode to match, which is several hours out…)

ok, xcode back on

yes i had tried that

and still got the error

my current arrangement (though before it was just all in testapp) is:

app>class A>class B>class C>include homography

class C calls homography

get duplicate symbol on gaussian

will figure it out this time

p.s. i also have to include ofxVectorMath, else i cant use ofxMatrix4x4

maybe that’s a hint to where I’m going wrong?

yep, wrapped it up and now that issues gone

will post when properly tested…

not sure where that was coming from

anyway, making a class with static functions

i’m probably the only one retarded enough to need this,

but here it is wrapped up

the functions are static so you can call

```
ofxHomographyHelper::findHomography(verticies_source, verticies_destination, your_ofxMatrix4x4.getPtr());
```

without instantiating the class

http://kimchiandchips.googlecode.com/files/ofxHomographyHelper.zip

I’m completely new to C++ and OpenFrameworks, and I was trying to experiment a bit with this interesting quad-warp examples I’ve found here on the topic.

I’m playing with several-quads setup, for something that could be used for projection-mapping experiments.

I have a quad class that seems to work, and I can initialize several quads independently, select an ‘active’ quad and warp and modify its vertices position. I even can add new quads on-the-fly (I’m using a std::vector class to store them) but I encounter problems if I try to use a keypress event to delete an existing quad and I get a segfault. I suspect it has to do with matrix push-and-pop sequence, but I was not able to debug the code due to my total lack of experience.

I was wondering if someone more experienced and skilled could have a look at my (rather naive) code and give me a hint or tip.

best to all, francesco

------- testApp.h

```
#ifndef _TEST_APP
#define _TEST_APP
#include "ofMain.h"
#include "ofAddons.h"
#include <vector>
//stupid ball class
class ball{
public:
ball(){
}
void setup(float x, float y, float r){
pos.x = x;
pos.y = y;
pos.z = r;
vel.x = 2.0;
vel.y = 1.6;
}
void update(int width, int height){
if( pos.x + pos.z >= width){
pos.x = width - pos.z;
vel.x *= -1;
}else if( pos.x - pos.z <= 0){
pos.x = pos.z;
vel.x *= -1;
}
if( pos.y + pos.z >= height){
pos.y = height - pos.z;
vel.y *= -1;
}else if( pos.y - pos.z <= 0){
pos.y = pos.z;
vel.y *= -1;
}
pos.x += vel.x;
pos.y += vel.y;
}
void draw(){
ofSetRectMode(OF_RECTMODE_CENTER);
ofCircle(pos.x, pos.y, pos.z);
ofSetRectMode(OF_RECTMODE_CORNER);
}
ofPoint pos;
ofPoint vel;
};
class quad{
public:
quad(){
}
ofPoint corners[4];
ofPoint src[4];
ofPoint dst[4];
//lets make a matrix for openGL
//this will be the matrix that peforms the transformation
GLfloat matrix[16];
ofTrueTypeFont ttf;
ofTrueTypeFont ttf2;
ofImage img;
ball balls[80];
int borderColor;
bool initialized;
void setup(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
initialized = True;
//loads load in some truetype fonts
ttf.loadFont("type/frabk.ttf", 22);
ttf2.loadFont("type/frabk.ttf", 14);
//lets load a test image too
img.loadImage("car.jpg");
//this is just for our gui / mouse handles
//this will end up being the destination quad we are warping too
//corners[0].x = 0.0;
//corners[0].y = 0.0;
//corners[1].x = 1.0;
//corners[1].y = 0.0;
//corners[2].x = 1.0;
//corners[2].y = 1.0;
//corners[3].x = 0.0;
//corners[3].y = 1.0;
corners[0].x = x1;
corners[0].y = y1;
corners[1].x = x2;
corners[1].y = y2;
corners[2].x = x3;
corners[2].y = y3;
corners[3].x = x4;
corners[3].y = y4;
//lets setup some stupid particles
for(int i = 0; i < 80; i++){
balls[i].setup(ofRandom(10, ofGetWidth() - 10), ofRandom(10, ofGetHeight()-10), ofRandom(5, 25));
balls[i].vel.x = ofRandom(1.5, 2.8);
balls[i].vel.y = ofRandom(1.5, 2.8);
}
}
void update() {
borderColor = 0xFF6600;
for(int i = 0; i < 80; i++){
balls[i].update(ofGetWidth(), ofGetHeight());
}
//we set matrix to the default - 0 translation
//and 1.0 scale for x y z and w
for(int i = 0; i < 16; i++){
if(i % 5 != 0) matrix[i] = 0.0;
else matrix[i] = 1.0;
}
//we set the warp coordinates
//source coordinates as the dimensions of our window
src[0].x = 0;
src[0].y = 0;
src[1].x = ofGetWidth();
src[1].y = 0;
src[2].x = ofGetWidth();
src[2].y = ofGetHeight();
src[3].x = 0;
src[3].y = ofGetHeight();
//corners are in 0.0 - 1.0 range
//so we scale up so that they are at the window's scale
for(int i = 0; i < 4; i++){
dst[i].x = corners[i].x * (float)ofGetWidth();
dst[i].y = corners[i].y * (float) ofGetHeight();
}
}
void draw() {
ofPushMatrix();
// find transformation matrix
findHomography(src, dst, matrix);
//finally lets multiply our matrix
//wooooo hoooo!
glMultMatrixf(matrix);
// -- NOW LETS DRAW!!!!!! -----
//test an image
ofSetColor(0xAAAAAA);
img.draw(20, 60);
//lets draw a bounding box
ofNoFill();
ofSetColor(borderColor);
ofRect(1, 1, ofGetWidth()-2, ofGetHeight()-2);
//our particles
ofEnableAlphaBlending();
ofSetColor(255, 120, 0, 130);
ofFill();
for(int i = 0; i < 40; i++)balls[i].draw();
ofDisableAlphaBlending();
//some text
ofSetColor(0x000000);
ttf.drawString("grab corners to warp openGL graphics", 28, 33);
ofSetColor(0xFFFFFF);
ttf.drawString("grab corners to warp openGL graphics", 30, 30);
ofSetColor(0x000000);
ttf2.drawString("warps images nicely too!", 558, 533);
ofSetColor(0xFF6600);
ttf2.drawString("warps images nicely too!", 560, 530);
ofSetColor(0x000000);
ttf2.drawString("press 'r' to reset", 558, 558);
ofSetColor(0xFFFFFF);
ttf2.drawString("press 'r' to reset", 560, 555);
ofPopMatrix();
}
void gaussian_elimination(float *input, int n){
// ported to c from pseudocode in
// [http://en.wikipedia.org/wiki/Gaussian-elimination](http://en.wikipedia.org/wiki/Gaussian-elimination)
float * A = input;
int i = 0;
int j = 0;
int m = n-1;
while (i < m && j < n){
// Find pivot in column j, starting in row i:
int maxi = i;
for(int k = i+1; k<m; k++){
if(fabs(A[k*n+j]) > fabs(A[maxi*n+j])){
maxi = k;
}
}
if (A[maxi*n+j] != 0){
//swap rows i and maxi, but do not change the value of i
if(i!=maxi)
for(int k=0;k<n;k++){
float aux = A[i*n+k];
A[i*n+k]=A[maxi*n+k];
A[maxi*n+k]=aux;
}
//Now A[i,j] will contain the old value of A[maxi,j].
//divide each entry in row i by A[i,j]
float A_ij=A[i*n+j];
for(int k=0;k<n;k++){
A[i*n+k]/=A_ij;
}
//Now A[i,j] will have the value 1.
for(int u = i+1; u< m; u++){
//subtract A[u,j] * row i from row u
float A_uj = A[u*n+j];
for(int k=0;k<n;k++){
A[u*n+k]-=A_uj*A[i*n+k];
}
//Now A[u,j] will be 0, since A[u,j] - A[i,j] * A[u,j] = A[u,j] - 1 * A[u,j] = 0.
}
i++;
}
j++;
}
//back substitution
for(int i=m-2;i>=0;i--){
for(int j=i+1;j<n-1;j++){
A[i*n+m]-=A[i*n+j]*A[j*n+m];
//A[i*n+j]=0;
}
}
}
void findHomography(ofPoint src[4], ofPoint dst[4], float homography[16]){
// create the equation system to be solved
//
// from: Multiple View Geometry in Computer Vision 2ed
// Hartley R. and Zisserman A.
//
// x' = xH
// where H is the homography: a 3 by 3 matrix
// that transformed to inhomogeneous coordinates for each point
// gives the following equations for each point:
//
// x' * (h31*x + h32*y + h33) = h11*x + h12*y + h13
// y' * (h31*x + h32*y + h33) = h21*x + h22*y + h23
//
// as the homography is scale independent we can let h33 be 1 (indeed any of the terms)
// so for 4 points we have 8 equations for 8 terms to solve: h11 - h32
// after ordering the terms it gives the following matrix
// that can be solved with gaussian elimination:
float P[8][9]={
{-src[0].x, -src[0].y, -1, 0, 0, 0, src[0].x*dst[0].x, src[0].y*dst[0].x, -dst[0].x }, // h11
{ 0, 0, 0, -src[0].x, -src[0].y, -1, src[0].x*dst[0].y, src[0].y*dst[0].y, -dst[0].y }, // h12
{-src[1].x, -src[1].y, -1, 0, 0, 0, src[1].x*dst[1].x, src[1].y*dst[1].x, -dst[1].x }, // h13
{ 0, 0, 0, -src[1].x, -src[1].y, -1, src[1].x*dst[1].y, src[1].y*dst[1].y, -dst[1].y }, // h21
{-src[2].x, -src[2].y, -1, 0, 0, 0, src[2].x*dst[2].x, src[2].y*dst[2].x, -dst[2].x }, // h22
{ 0, 0, 0, -src[2].x, -src[2].y, -1, src[2].x*dst[2].y, src[2].y*dst[2].y, -dst[2].y }, // h23
{-src[3].x, -src[3].y, -1, 0, 0, 0, src[3].x*dst[3].x, src[3].y*dst[3].x, -dst[3].x }, // h31
{ 0, 0, 0, -src[3].x, -src[3].y, -1, src[3].x*dst[3].y, src[3].y*dst[3].y, -dst[3].y }, // h32
};
gaussian_elimination(&P[0][0],9);
// gaussian elimination gives the results of the equation system
// in the last column of the original matrix.
// opengl needs the transposed 4x4 matrix:
float aux_H[]={ P[0][8],P[3][8],0,P[6][8], // h11 h21 0 h31
P[1][8],P[4][8],0,P[7][8], // h12 h22 0 h32
0 , 0,0,0, // 0 0 0 0
P[2][8],P[5][8],0,1}; // h13 h23 0 h33
for(int i=0;i<16;i++) homography[i] = aux_H[i];
}
};
class testApp : public ofSimpleApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased();
int whichCorner;
ofTrueTypeFont ttf;
std::vector<quad> quads;
//quad quads[10];
int nOfQuads;
int activeQuad;
};
#endif
```

---------------------- testApp.cpp

```
#include "testApp.h"
#include "stdio.h"
#include <iostream>
//--------------------------------------------------------------
void testApp::setup(){
//we run at 60 fps!
ofSetVerticalSync(true);
ttf.loadFont("type/frabk.ttf", 11);
//for(int i = 0; i<10; i++){
//quads[i].setup();
//}
//quads[0].setup(0.0,0.0,0.5,0.0,0.5,0.5,0.0,0.5);
//quads[1].setup(0.5,0.0,1.0,0.0,1.0,0.5,0.5,0.5);
//quads[2].setup(0.0,0.5,0.5,0.5,0.5,1.0,0.0,1.0);
//quads[3].setup(0.5,0.5,1.0,0.5,1.0,1.0,0.5,1.0);
quads.reserve(16);
quad one;
one.setup(0.0,0.0,0.5,0.0,0.5,0.5,0.0,0.5);
quad two;
two.setup(0.5,0.0,1.0,0.0,1.0,0.5,0.5,0.5);
quad three;
three.setup(0.0,0.5,0.5,0.5,0.5,1.0,0.0,1.0);
quad four;
four.setup(0.5,0.5,1.0,0.5,1.0,1.0,0.5,1.0);
quads.push_back(one);
quads.push_back(two);
quads.push_back(three);
quads.push_back(four);
activeQuad = 0;
}
//--------------------------------------------------------------
void testApp::update(){
nOfQuads = quads.size();
ofBackground(20, 20, 20);
ofSetWindowShape(800, 600);
for(int i = 0; i < nOfQuads; i++){
quads[i].update();
}
}
//--------------------------------------------------------------
void testApp::draw(){
nOfQuads = quads.size();
quads[activeQuad].borderColor = 0xFFFFFF;
for(int i = 0; i < nOfQuads; i++){
quads[i].draw();
}
ofSetColor(0xFFFFFF);
ttf.drawString("active quad: "+ofToString(activeQuad), 30, 570);
}
//--------------------------------------------------------------
void testApp::keyPressed(int key){
if ( key =='r' || key == 'R' )
{
quads[activeQuad].corners[0].x = 0.0;
quads[activeQuad].corners[0].y = 0.0;
quads[activeQuad].corners[1].x = 1.0;
quads[activeQuad].corners[1].y = 0.0;
quads[activeQuad].corners[2].x = 1.0;
quads[activeQuad].corners[2].y = 1.0;
quads[activeQuad].corners[3].x = 0.0;
quads[activeQuad].corners[3].y = 1.0;
}
if ( key =='>' )
{
activeQuad += 1;
if (activeQuad > quads.size()-1) {activeQuad = 0;}
}
if ( key =='<' )
{
activeQuad -= 1;
if (activeQuad < 0) {activeQuad = quads.size()-1;}
}
if ( key =='a' )
{
if (quads.size() < 16) {
quad i;
i.setup(0.25,0.25,0.75,0.25,0.75,0.75,0.25,0.75);
quads.push_back(i);
activeQuad = quads.size()-1;
}
}
if ( key =='d' )
{
if (quads.size() > 1) {
quads.erase(quads.begin()+activeQuad);
activeQuad -= 1;
nOfQuads = quads.size();
}
}
}
//--------------------------------------------------------------
void testApp::keyReleased(int key){
}
//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
float scaleX = (float)x / ofGetWidth();
float scaleY = (float)y / ofGetHeight();
if(whichCorner >= 0){
quads[activeQuad].corners[whichCorner].x = scaleX;
quads[activeQuad].corners[whichCorner].y = scaleY;
}
}
//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
float smallestDist = 1.0;
whichCorner = -1;
for(int i = 0; i < 4; i++){
float distx = quads[activeQuad].corners[i].x - (float)x/ofGetWidth();
float disty = quads[activeQuad].corners[i].y - (float)y/ofGetHeight();
float dist = sqrt( distx * distx + disty * disty);
if(dist < smallestDist && dist < 0.1){
whichCorner = i;
smallestDist = dist;
}
}
}
//--------------------------------------------------------------
void testApp::mouseReleased(){
whichCorner = -1;
}
```

started a projection-mapping simple tool experiment using as a foundation the code provided in this thread.

first code ever in openframeworks and c++ for me.

hi

i have used the matrix and cvfindhomography code for a projected that uses 2 hd projectors.

it works pretty good.

the projectors project on to a conveyor belt. on the belt we place real objects and on to the moving objects we projected images.

but i have noticed that the position of the real and projected images do not always match. it changes through out the projection.

it matches at the start (left side of projection), lags behind towards the middle and is a head towards the right.

i know memo mentioned that short throw lens need some sort of un-warping but this is a beng w6000 with a normal lens.

here is a link to the project:

http://www.lozano-hemmer.com/please-emp-…-ockets.php

here is my code to help make the matrix map:

www.lozano-hemmer.com/ss/keystoner5.zip

any ideas what is going on?

thanks,

stephan.

@arturo thanks so much for this code!

I have a question - does it matter which order the points 0-3 are defined in? I’m using them with the ofxSimpleGUITooQuadWarper which seems to use points defined from the top left clockwise. My destPoints are also defined as such but I’m getting unexpected results.

thanks again.

Seb

Ah. After some hair pulling, I figured it out. If you take Arturo’s code :

```
ofMatrix4x4 H = findHomography(sourcePoints, destPoints);
ofVec3f v(xPos,yPos);
ofVec3f t = v * H;
```

… it doesn’t work. Instead I switched H and v and now it works!

```
ofVec3f t = H * v;
```

Just thought I’d let you know in case this was a bug, or maybe just a slight change in the ofMatrix4x4 or ofVec2f objects.

cheers!

Seb

I’m curious about the opposite of this code:

```
ofxMatrix4x4 H = findHomography(src,dst);
ofxVec2f v(x,y);
ofxVec2f t = v*H;
```

Something like:

```
ofxMatrix4x4 H = findHomography(src,dst);
ofxVec2f t(x,y);
ofxVec2f v = t/H;
```

Maybe someone can point me to the right direction?

I solved it in a very simple way - just by swapping the source points with destination points in the find homography function call. Like the following:

```
ofxMatrix4x4 H = findHomography(dst,src);
ofxVec2f t(x,y);
ofxVec2f v = t*H;
```

That’s it!

Hi

I’m very interested in your code but the link doesnt work anymore.

Any help?