Hello,
first time...first kiss...so please forgive any mistakes.
In this great PROCESSING (thanks to all the constructors) I´m puzzling a structured light 3D scanning application based on 3 phase shifted fringe patterns (different than the Gray code pattern sequence): PROCESING feeds the projector with the patterns, grabs 3 synchronized images + a texture shot and processes them to 3D.
So far so good.
To improve the results I need some better calibration of the cam - means: processing the input images, to recalculate the cam's lense distortion and rotation in 3D.
I´m trying to do this in a more interactive way than some automatic calibration ( as Tsai or something similar). So my idea is to do a complementary (to the reality) distortion of the images in Processing before saving the images.
I found that peasycam and patchy make it possible to process the video feed of a webcam in 3D. So all I would need is matching of this 3D to a 2D overlay. So if the webcam gives an image of an calibration pattern, one can rotate and distort that result till it fits to a corresponding pattern in the overlay.
So my questions:
The only way to create such an 2D overlay (or a 3D object that moves WITH the peasycam) I found until now is to use text. Are there some other ways to draw such a pattern?
Is there an idea to extract the markers from the video image and place them fitting to the overlay? (which means the peasycam has to move AND the controlPoints of the Patch object may need modification).
Besides my application, that would also be interesting to calibrate a videoprojector at any odd projections surface.
Here`s a beginner's code to illustrate:
Code:
import peasy.*;
import patchy.*;
import processing.video.*;
Capture proscreen;
Patch patch;
BoundingVolume bounds;
PeasyCam cam;
PFont font;
int b = 25;
int a = 70;
float distort = 0;
double distance = 21;
boolean calib = false;
boolean isMouseControlled = true;
void setup()
{
size(960, 740, P3D);
stroke (255);
final double[][] cpX = new double[][] { { 0 ,4*b/3, 8*b/3, 4*b }, { 0, 4*b/3, 8*b/3, 4*b },
{ 0, 4*b/3, 8*b/3, 4*b }, { 0, 4*b/3, 8*b/3, 4*b } };
final double[][] cpZ = new double[][] { { - distort, - distort, - distort, - distort }, { - distort, 0, 0, - distort },
{ - distort, 0, 0, - distort }, { - distort, - distort, - distort, - distort } };
final double[][] cpY = new double[][] { { 0, 0, 0, 0 }, { (3*b/3), (3*b/3), (3*b/3), (3*b/3) },
{ (6*b/3), (6*b/3), (6*b/3), (6*b/3) }, { 3*b, 3*b, 3*b, 3*b } };
patch = Patch.create(Patch.CATMULL_ROM, cpX, cpY, cpZ);
bounds = patch.getBounds();
cam = new PeasyCam(this, bounds.x.center(), bounds.y.center(), distance, 0);
proscreen = new Capture(this, 640,480, 30);
}
public void draw()
{
background(0);
stroke (255);
final double[][] cpX = new double[][] { { 0 ,4*b/3, 8*b/3, 4*b }, { 0, 4*b/3, 8*b/3, 4*b },
{ 0, 4*b/3, 8*b/3, 4*b }, { 0, 4*b/3, 8*b/3, 4*b } };
final double[][] cpZ = new double[][] { { - distort, - distort, - distort, - distort }, { - distort, 0, 0, - distort },
{ - distort, 0, 0, - distort }, { - distort, - distort, - distort, - distort } };
final double[][] cpY = new double[][] { { 0, 0, 0, 0 }, { (3*b/3), (3*b/3), (3*b/3), (3*b/3) },
{ (6*b/3), (6*b/3), (6*b/3), (6*b/3) }, { 3*b, 3*b, 3*b, 3*b } };
patch = Patch.create(Patch.CATMULL_ROM, cpX, cpY, cpZ);
pushMatrix();
noStroke();
patch.draw(this, proscreen);
fill(0);
popMatrix();
if ( calib == false)
instructions();
}
private void instructions()
{ textMode(SCREEN);
font = loadFont("CourierNew-12.vlw");
textFont(font, 12);
fill(255, 50, 0);
textAlign(LEFT);
text("Double click to call the frame to start.Drag to adjust picture to grid. Right-drag to zoom. To lock the screen hit C. Distortion: " + distort, 10, height - 8);
font = loadFont("CourierNewPSMT-24.vlw");
textFont(font, 24);
textAlign(CENTER);
text("o", a,a+5);
text("o", a,a+(height-2*a)/4+5);
text("o", a,height/2+5);
text("o", a,a+3*(height-2*a)/4+5);
text("o", a,height - a+5);
text("o", a+(width-2*a)/4,a+5);
text("o", a+(width-2*a)/4,a+(height-2*a)/4+5);
text("o", a+(width-2*a)/4,height/2+5);
text("o", a+(width-2*a)/4,a+3*(height-2*a)/4+5);
text("o", a+(width-2*a)/4,height - a+5);
text("o", width/2,a+5);
text("o", width/2,a+(height-2*a)/4+5);
text("o", width/2,height/2+5);
text("o", width/2,a+3*(height-2*a)/4+5);
text("o", width/2,height - a+5);
text("o", a+3*(width-2*a)/4,a+5);
text("o", a+3*(width-2*a)/4,a+(height-2*a)/4+5);
text("o", a+3*(width-2*a)/4,height/2+5);
text("o", a+3*(width-2*a)/4,a+3*(height-2*a)/4+5);
text("o", a+3*(width-2*a)/4,height - a+5);
text("o", width - a,a+5);
text("o", width - a,a+(height-2*a)/4+5);
text("o", width - a,height/2+5);
text("o", width - a,a+3*(height-2*a)/4+5);
text("o", width - a,height - a+5);
}
void captureEvent(Capture proscreen) {
proscreen.read();
}
void keyPressed ()
{
if ( key == '1' )
{
distort += 0.25;
}
else if ( key == '2' )
{
distort -= 0.25;
}
if ( key == 'x' )
{
cam.rotateX (0.001) ;
}
if ( key == 'X' )
{
cam.rotateX (-0.001) ;
}
if ( key == 'y' )
{
cam.rotateY (0.001) ;
}
if ( key == 'Y' )
{
cam.rotateY (-0.001) ;
}
if ( key == 'a' )
{
cam.rotateZ (0.001) ;
}
if ( key == 'A' )
{
cam.rotateZ (-0.001) ;
}
if ( key == 'C' )
{
calib = false ;
cam.setMouseControlled(isMouseControlled = true);
}
if ( key == 'c' )
{
calib = true ;
cam.setMouseControlled(isMouseControlled = false);
}
}
Any help appreciated!