/*
* Copyright Inria and Bordeaux University.
* Author Jeremy Laviole. jeremy.laviole@inria.fr
* PapAR project is the open-source version of the
* PapARt project. License is LGPLv3, distributed with the sources.
* This project can also distributed with standard commercial
* licence for closed-sources projects.
*/
package fr.inria.papart.procam;
import fr.inria.papart.calibration.HomographyCalibration;
import fr.inria.papart.calibration.HomographyCreator;
import fr.inria.papart.calibration.PlaneCalibration;
import fr.inria.papart.calibration.PlaneCreator;
import fr.inria.papart.procam.camera.Camera.PixelFormat;
import fr.inria.papart.procam.display.ARDisplay;
import org.bytedeco.javacpp.opencv_imgproc.*;
import org.bytedeco.javacv.CameraDevice;
import org.bytedeco.javacv.CameraDevice.Settings;
import org.bytedeco.javacv.ProjectorDevice;
import org.bytedeco.javacpp.opencv_imgproc;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_calib3d.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import processing.core.*;
import static processing.core.PConstants.ARGB;
import static processing.core.PConstants.RGB;
import processing.opengl.Texture;
import toxi.geom.Matrix4x4;
import toxi.geom.Vec3D;
/**
*
* @author jeremy
*/
public class Utils {
static public final String LibraryName = "PapAR";
static public String getLibraryFolder(String libname) {
return getLibrariesFolder() + "/libraries/" + libname;
}
static public String getLibrariesFolder() {
// This is used, as Papart classes are often linked to another folder...
URL main = Matrix4x4.class.getResource("Matrix4x4.class");
// URL main = ARDisplay.class.getResource("ARDisplay.class");
String tmp = main.getPath();
System.out.println("path " + tmp);
// its in a jar
if (tmp.contains("!")) {
tmp = tmp.substring(0, tmp.indexOf('!'));
tmp = tmp.replace("file:", "");
// tmp = tmp.replace("file:/", ""); TODO: OS check ?
}
File f = new File(tmp);
if (!f.exists()) {
System.err.println("Error in loading the Sketchbook folder.");
}
// if the file is within a library/lib folder
if (f.getParentFile().getAbsolutePath().endsWith(("/lib"))) {
// pathToSketchbook/libraries/myLib/library/lib/myLib.jar
f = f.getParentFile().getParentFile().getParentFile().getParentFile();
} else {
// pathToSketchbook/libraries/myLib/library/myLib.jar
f = f.getParentFile().getParentFile().getParentFile();
}
return f.getAbsolutePath();
}
static public String getPapartFolder() {
// String sketchbook = java.lang.System.getenv("SKETCHBOOK");
// if (sketchbook != null) {
// System.out.println("Found SKETCHBOOK environment variable.");
// return sketchbook + "/libraries/" + LibraryName;
// }
return getLibrariesFolder() + "/" + LibraryName;
}
static public PVector mult(PMatrix3D mat, PVector source, PVector target) {
if (target == null) {
target = new PVector();
}
target.x = mat.m00 * source.x + mat.m01 * source.y + mat.m02 * source.z + mat.m03;
target.y = mat.m10 * source.x + mat.m11 * source.y + mat.m12 * source.z + mat.m13;
target.z = mat.m20 * source.x + mat.m21 * source.y + mat.m22 * source.z + mat.m23;
float tw = mat.m30 * source.x + mat.m31 * source.y + mat.m32 * source.z + mat.m33;
if (tw != 0 && tw != 1) {
target.div(tw);
}
return target;
}
static public Vec3D toVec(PVector p) {
return new Vec3D(p.x, p.y, p.z);
}
static public boolean colorDist(int c1, int c2, int threshold) {
int r1 = c1 >> 16 & 0xFF;
int g1 = c1 >> 8 & 0xFF;
int b1 = c1 >> 0 & 0xFF;
int r2 = c2 >> 16 & 0xFF;
int g2 = c2 >> 8 & 0xFF;
int b2 = c2 >> 0 & 0xFF;
int dr = PApplet.abs(r1 - r2);
int dg = PApplet.abs(g1 - g2);
int db = PApplet.abs(b1 - b2);
return dr < threshold && dg < threshold && db < threshold;
}
// TODO: throws ...
public static void savePMatrix3D(PApplet pa, PMatrix3D mat, String filename) {
String[] lines = new String[16];
lines[0] = Float.toString(mat.m00);
lines[1] = Float.toString(mat.m01);
lines[2] = Float.toString(mat.m02);
lines[3] = Float.toString(mat.m03);
lines[4] = Float.toString(mat.m10);
lines[5] = Float.toString(mat.m11);
lines[6] = Float.toString(mat.m12);
lines[7] = Float.toString(mat.m13);
lines[8] = Float.toString(mat.m20);
lines[9] = Float.toString(mat.m21);
lines[10] = Float.toString(mat.m22);
lines[11] = Float.toString(mat.m23);
lines[12] = Float.toString(mat.m30);
lines[13] = Float.toString(mat.m31);
lines[14] = Float.toString(mat.m32);
lines[15] = Float.toString(mat.m33);
pa.saveStrings(filename, lines);
}
public static void addPMatrix3D(PMatrix3D src, PMatrix3D toAdd) {
src.m00 += toAdd.m00;
src.m01 += toAdd.m01;
src.m02 += toAdd.m02;
src.m03 += toAdd.m03;
src.m10 += toAdd.m10;
src.m11 += toAdd.m11;
src.m12 += toAdd.m12;
src.m13 += toAdd.m13;
src.m20 += toAdd.m20;
src.m21 += toAdd.m21;
src.m22 += toAdd.m22;
src.m23 += toAdd.m23;
src.m30 += toAdd.m30;
src.m31 += toAdd.m31;
src.m32 += toAdd.m32;
src.m33 += toAdd.m33;
}
static public void scaleMat(PMatrix3D mat, float scale) {
//applscale(scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1);
mat.m00 *= scale;
mat.m01 *= scale;
mat.m02 *= scale;
mat.m03 *= scale;
mat.m10 *= scale;
mat.m11 *= scale;
mat.m12 *= scale;
mat.m13 *= scale;
mat.m20 *= scale;
mat.m21 *= scale;
mat.m22 *= scale;
mat.m23 *= scale;
mat.m30 *= scale;
mat.m31 *= scale;
mat.m32 *= scale;
mat.m33 *= scale;
}
public static PMatrix3D loadPMatrix3D(PApplet pa, String filename) throws FileNotFoundException {
String[] lines = pa.loadStrings(filename);
if (lines == null) {
throw new FileNotFoundException(filename);
}
PMatrix3D mat = new PMatrix3D(Float.parseFloat(lines[0]), Float.parseFloat(lines[1]), Float.parseFloat(lines[2]), Float.parseFloat(lines[3]),
Float.parseFloat(lines[4]), Float.parseFloat(lines[5]), Float.parseFloat(lines[6]), Float.parseFloat(lines[7]),
Float.parseFloat(lines[8]), Float.parseFloat(lines[9]), Float.parseFloat(lines[10]), Float.parseFloat(lines[11]),
Float.parseFloat(lines[12]), Float.parseFloat(lines[13]), Float.parseFloat(lines[14]), Float.parseFloat(lines[15]));
return mat;
}
static public IplImage createImageFrom(IplImage imgIn, PImage Pout) {
// TODO: avoid this creation !!
CvSize outSize = new CvSize();
outSize.width(Pout.width);
outSize.height(Pout.height);
IplImage imgOut = cvCreateImage(outSize, // size
imgIn.depth(), // depth
imgIn.nChannels());
// imgIn.w
return imgOut;
}
static public IplImage createImageFrom(IplImage imgIn) {
// TODO: avoid this creation !!
CvSize outSize = new CvSize();
outSize.width(imgIn.width());
outSize.height(imgIn.height());
IplImage imgOut = cvCreateImage(outSize, // size
imgIn.depth(), // depth
imgIn.nChannels());
// imgIn.w
return imgOut;
}
static public IplImage createImageFrom(PImage in) {
// TODO: avoid this creation !!
CvSize outSize = new CvSize();
outSize.width(in.width);
outSize.height(in.height);
IplImage imgOut = null;
if (in.format == RGB) {
imgOut = cvCreateImage(outSize, // size
IPL_DEPTH_8U, // depth
3);
}
if (in.format == ARGB) {
imgOut = cvCreateImage(outSize, // size
IPL_DEPTH_8U, // depth
4);
}
// imgIn.w
return imgOut;
}
static public void createAnaglyph(PImage imgL, PImage imgR, PImage imgOut) {
imgL.loadPixels();
imgR.loadPixels();
imgOut.loadPixels();
int[] pL = imgL.pixels;
int[] pR = imgR.pixels;
int[] pO = imgOut.pixels;
for (int i = 0; i < pL.length; i++) {
pO[i] = (pR[i] >> 16) << 16
| (pL[i] >> 8) & 0xFF << 8
| pL[i] & 0xFF;
// pO[i] = pL[i];
}
imgOut.updatePixels();
// imgL.updatePixels();
}
static public CvMat createHomography(PVector[] in, PVector[] out) {
CvMat srcPoints;
CvMat dstPoints;
int nbPoints = in.length;
CvMat homography;
// TODO: no create map
srcPoints = cvCreateMat(2, in.length, CV_32FC1);
dstPoints = cvCreateMat(2, in.length, CV_32FC1);
homography = cvCreateMat(3, 3, CV_32FC1);
for (int i = 0; i < in.length; i++) {
srcPoints.put(i, in[i].x);
srcPoints.put(i + nbPoints, in[i].y);
dstPoints.put(i, out[i].x);
dstPoints.put(i + nbPoints, out[i].y);
}
cvFindHomography(srcPoints, dstPoints, homography);
// It is better to use : GetPerspectiveTransform
return homography;
}
// TODO: finish this, find another source...
// http://planning.cs.uiuc.edu/node103.html
static public PVector getRotations(PMatrix3D mat) {
PVector r = new PVector();
r.z = PApplet.atan(mat.m10 / mat.m00);
r.y = PApplet.atan(-mat.m21 / PApplet.sqrt(mat.m21 * mat.m21 + mat.m22 * mat.m22));
r.x = PApplet.atan(-mat.m21 / PApplet.sqrt(mat.m21 * mat.m21 + mat.m22 * mat.m22));
return null;
}
// TO USE INSIDE THE DRAW FUNCTION
// TODO: Experimental -> To validate...
// static public Texture createTextureFrom(PApplet parent, IplImage img) {
// Texture tex = null;
//
// // We suppose... Depth = 3 : BGR and Depth = 4 : RGBA (even though it is written ARGB for Processing...)
// if (img.nChannels() == 3) {
// tex = new Texture(img.width(), img.height(), PApplet.RGB);
// }
// if (img.nChannels() == 4) {
// tex = new Texture(img.width(), img.height(), PApplet.ARGB);
// }
// return tex;
// }
static public void updateTexture(IplImage img, Texture tex) {
System.out.println("Update Texture broken ? May Require CustomTexture...");
// if (img.nChannels() == 3) {
// tex.putBuffer(GL.GL_BGR, GL.GL_UNSIGNED_BYTE, img.getIntBuffer());
// }
// if (img.nChannels() == 4) {
// tex.putBuffer(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, img.getIntBuffer());
// }
}
static public void remapImage(PVector[] in, PVector[] out, IplImage imgIn, IplImage imgTmp, PImage Pout) {
CvMat srcPoints;
CvMat dstPoints;
int nbPoints = in.length;
CvMat homography;
// TODO: no create map
srcPoints = cvCreateMat(2, in.length, CV_32FC1);
dstPoints = cvCreateMat(2, in.length, CV_32FC1);
homography = cvCreateMat(3, 3, CV_32FC1);
for (int i = 0; i < in.length; i++) {
srcPoints.put(i, in[i].x);
srcPoints.put(i + nbPoints, in[i].y);
dstPoints.put(i, out[i].x);
dstPoints.put(i + nbPoints, out[i].y);
}
cvFindHomography(srcPoints, dstPoints, homography);
// It is better to use : GetPerspectiveTransform
opencv_imgproc.cvWarpPerspective(imgIn, imgTmp, homography);
// opencv_imgproc.CV_INTER_LINEAR ); // opencv_imgproc.CV_WARP_FILL_OUTLIERS);
// getFillColor());
IplImageToPImage(imgTmp, false, Pout);
}
static public void remapImage(CvMat homography, IplImage imgIn, IplImage imgTmp, PImage Pout) {
opencv_imgproc.cvWarpPerspective(imgIn, imgTmp, homography);
// opencv_imgproc.CV_INTER_LINEAR ); // opencv_imgproc.CV_WARP_FILL_OUTLIERS);
// getFillColor());
IplImageToPImage(imgTmp, false, Pout);
}
static public void remapImageIpl(CvMat homography, IplImage imgIn, IplImage imgOut) {
opencv_imgproc.cvWarpPerspective(imgIn, imgOut, homography);
// opencv_imgproc.CV_INTER_LINEAR ); // opencv_imgproc.CV_WARP_FILL_OUTLIERS);
// getFillColor());
}
static public int getColor(IplImage img, int x, int y, boolean RGB) {
if (img.nChannels() == 3) {
ByteBuffer buff = img.getByteBuffer();
int offset = (img.width() * y + x) * 3;
if (RGB) {
return (buff.get(offset) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset + 2) & 0xFF);
} else {
return (buff.get(offset + 2) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset) & 0xFF);
}
}
// Operation not supported
return 0;
}
// TODO: clean all this !
static public void IplImageToPImage(IplImage img, PApplet applet, boolean RGB, PImage ret) {
IplImageToPImage(img, RGB, ret);
}
static public void IplImageToPImage(IplImage img, PixelFormat format, PImage ret) {
if (format == PixelFormat.RGB) {
IplImageToPImage(img, true, ret);
}
if (format == PixelFormat.BGR) {
IplImageToPImage(img, false, ret);
}
}
static public void IplImageToPImage(IplImage img, PImage ret) {
IplImageToPImage(img, true, ret);
}
static int conversionCount = 0;
static public void IplImageToPImage(IplImage img, boolean RGB, PImage ret) {
// conversionCount++;
// if (conversionCount % 600 == 0) {
// System.gc();
// }
assert (img.width() == ret.width);
assert (img.height() == ret.height);
//= new BufferedImage();
if (img.nChannels() == 3) {
ByteBuffer buff = img.getByteBuffer();
// PImage ret = new PImage(img.width(), img.height(), PApplet.RGB);
ret.loadPixels();
if (RGB) {
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 3;
ret.pixels[i] = (buff.get(offset) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset + 2) & 0xFF);
}
} else {
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 3;
ret.pixels[i] = (buff.get(offset + 2) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset) & 0xFF);
}
}
}
if (img.nChannels() == 4) {
ByteBuffer buff = img.getByteBuffer();
// PImage ret = new PImage(img.width(), img.height(), PApplet.RGB);
ret.loadPixels();
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 4;
// ret.pixels[i] = applet.color(buff.get(offset + 0) & 0xff, buff.get(offset + 1) & 0xFF, buff.get(offset + 2) & 0xff);
ret.pixels[i] = (0xFF) << 24
| (buff.get(offset) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset + 2) & 0xFF);
}
}
if (img.nChannels() == 1) {
// TODO: no more allocations.
ByteBuffer buff = img.getByteBuffer();
byte[] arr = new byte[img.width() * img.height()];
buff.get(arr);
for (int i = 0; i < img.width() * img.height(); i++) {
int d = (arr[i] & 0xFF);
ret.pixels[i] = d;
}
}
ret.updatePixels();
}
static public void byteBufferBRGtoARGB(ByteBuffer bgr, ByteBuffer argb) {
byte[] tmpArr = new byte[3];
for (int i = 0; i < bgr.capacity(); i += 3) {
bgr.get(tmpArr);
argb.put(tmpArr[2]);
argb.put(tmpArr[1]);
argb.put(tmpArr[0]);
argb.put((byte) 255);
}
argb.rewind();
}
// TODO
private static byte[] kinectByteArray = null;
static public void IplImageToPImageKinect(IplImage img, boolean RGB, PImage ret) {
// conversionCount++;
// if (conversionCount % 30 == 0) {
// System.gc();
// }
assert (img.width() == ret.width);
assert (img.height() == ret.height);
// BufferedImage bimg = new BufferedImage();
if (img.nChannels() == 3) {
System.out.println("3 channels");
ByteBuffer buff = img.getByteBuffer();
// PImage ret = new PImage(img.width(), img.height(), PApplet.RGB);
ret.loadPixels();
if (RGB) {
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 3;
// ret.pixels[i] = applet.color(buff.get(offset + 0) & 0xff, buff.get(offset + 1) & 0xFF, buff.get(offset + 2) & 0xff);
ret.pixels[i] = (buff.get(offset) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset + 2) & 0xFF);
}
} else {
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 3;
// ret.pixels[i] = applet.color(buff.get(offset + 0) & 0xff, buff.get(offset + 1) & 0xFF, buff.get(offset + 2) & 0xff);
ret.pixels[i] = (buff.get(offset + 2) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset) & 0xFF);
}
}
} else {
if (img.nChannels() == 1) {
////////////// Kinect Depth //////////////
ByteBuffer buff = img.getByteBuffer();
if (Utils.kinectByteArray == null) {
kinectByteArray = new byte[2 * img.width() * img.height()];
}
// else {
// Arrays.fill(kinectByteArray, (byte) 0);
// }
buff.get(kinectByteArray);
for (int i = 0; i < img.width() * img.height() * 2; i += 2) {
int d = (kinectByteArray[i] & 0xFF) << 8
| (kinectByteArray[i + 1] & 0xFF);
ret.pixels[i / 2] = d;
// ret.pixels[i] =
// (buff.get(i) & 0xFF) << 16
// | (buff.get(i) & 0xFF) << 8
// | (buff.get(i) & 0xFF);
}
}
}
// buff = null;
ret.updatePixels();
}
/**
*
* Deprecated
*/
// static public void PImageToIplImage(PImage src, IplImage dst) {
// dst.copyFrom((BufferedImage) src.getImage());
// }
static public void PImageToIplImage2(IplImage img, boolean RGB, PImage ret) {
ByteBuffer buff = img.getByteBuffer();
ret.loadPixels();
if (RGB) {
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 3;
ret.pixels[i] = (buff.get(offset) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset + 2) & 0xFF);
}
} else {
for (int i = 0; i < img.width() * img.height(); i++) {
int offset = i * 3;
ret.pixels[i] = (buff.get(offset + 2) & 0xFF) << 16
| (buff.get(offset + 1) & 0xFF) << 8
| (buff.get(offset) & 0xFF);
}
}
ret.updatePixels();
}
// int int 12 double 4 double
static final int SIZE_OF_PARAM_SET = 4 + 4 + (3 * 4 * 8) + (4 * 8);
static public void convertARParam(PApplet pa, String inputYAML, String outputDAT, int w, int h) throws Exception {
CameraDevice cam = null;
CameraDevice[] c = CameraDevice.read(inputYAML);
if (c.length > 0) {
cam = c[0];
}
double[] proj = cam.cameraMatrix.get();
double[] distort = cam.distortionCoeffs.get();
OutputStream os = pa.createOutput(outputDAT);
byte[] buf = new byte[SIZE_OF_PARAM_SET];
ByteBuffer bb = ByteBuffer.wrap(buf);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putInt(w);
bb.putInt(h);
//Projection
int k = 0;
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 3; i++) {
bb.putDouble(proj[k++]);
}
bb.putDouble(0);
}
bb.putDouble(proj[2]);
bb.putDouble(proj[5]);
bb.putDouble(100);
bb.putDouble(1d);
os.write(buf);
os.flush();
os.close();
pa.println("Conversion done !");
return;
}
static public void convertARParam2(PApplet pa, String fileName, String outputDAT) throws Exception {
CameraDevice cam = null;
ProjectiveDeviceP pdp = ProjectiveDeviceP.loadCameraDevice(pa, fileName);
// CameraDevice[] c = CameraDevice.read(fileName);
// if (c.length > 0) {
// cam = c[0];
// }
OutputStream os = pa.createOutput(outputDAT);
PrintWriter pw = pa.createWriter(outputDAT);
StringBuffer sb = new StringBuffer();
// From ARToolkitPlus...
//http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
sb.append("ARToolKitPlus_CamCal_Rev02\n");
sb.append(pdp.getWidth()).append(" ").append(pdp.getHeight()).append(" ");
// cx cy fx fy
sb.append(pdp.getCx()).append(" ").append(pdp.getCy())
.append(" ").append(pdp.getFx()).
append(" ").append(pdp.getFy()).append(" ");
// alpha_c // skew factor
sb.append("0 ").append(" ");
// kc(1 - x) -> 6 values
if (pdp.handleDistorsions()) {
double[] distort = ((CameraDevice) pdp.getDevice()).distortionCoeffs.get();
for (int i = 0; i < distort.length; i++) {
sb.append(distort[i]).append(" ");
}
// fill with 0s the end.
for (int i = distort.length; i < 5; i++) {
sb.append("0 ");
}
} else {
for (int i = 0; i < 5; i++) {
sb.append("0 ");
}
}
// undist iterations
sb.append("10\n");
pw.print(sb);
pw.flush();
pw.close();
}
static public void convertProjParam(PApplet pa, String inputYAML, String outputDAT, int w, int h) throws Exception {
ProjectorDevice proj = null;
ProjectorDevice[] p = ProjectorDevice.read(inputYAML);
if (p.length > 0) {
proj = p[0];
}
double[] projM = proj.cameraMatrix.get();
double[] distort = proj.distortionCoeffs.get();
OutputStream os = pa.createOutput(outputDAT);
byte[] buf = new byte[SIZE_OF_PARAM_SET];
ByteBuffer bb = ByteBuffer.wrap(buf);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putInt(w);
bb.putInt(h);
//projection
int k = 0;
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 3; i++) {
bb.putDouble(projM[k++]);
}
bb.putDouble(0);
}
// ARtoolkit distortion
bb.putDouble(projM[2]);
bb.putDouble(projM[5]);
bb.putDouble(0);
bb.putDouble(1d);
os.write(buf);
os.flush();
os.close();
pa.println("Conversion done !");
return;
}
// static public void convertARParam(PApplet pa, String inputYAML, String outputDAT, int w, int h) throws Exception {
//
// CameraDevice cam = null;
//
// CameraDevice[] c = CameraDevice.read(inputYAML);
// if (c.length > 0) {
// cam = c[0];
// }
//
// double[] proj = cam.cameraMatrix.get();
// double[] distort = cam.distortionCoeffs.get();
//
// OutputStream os = pa.createOutput(outputDAT);
//
// byte[] buf = new byte[SIZE_OF_PARAM_SET];
// ByteBuffer bb = ByteBuffer.wrap(buf);
// bb.order(ByteOrder.BIG_ENDIAN);
//
// bb.putInt(w);
// bb.putInt(h);
//
// //Projection
// int k = 0;
// for (int j = 0; j < 3; j++) {
// for (int i = 0; i < 3; i++) {
// bb.putDouble(proj[k++]);
// }
// bb.putDouble(0);
// }
//
// //distortion
// for (int i = 0; i < 4; i++) {
// bb.putDouble(distort[i]);
// }
//
// os.write(buf);
// os.flush();
// os.close();
//
// pa.println("Conversion done !");
// return;
// }
//
// static public void convertProjParam(PApplet pa, String inputYAML, String outputDAT, int w, int h) throws Exception {
//
// ProjectorDevice proj = null;
//
// ProjectorDevice[] p = ProjectorDevice.read(inputYAML);
// if (p.length > 0) {
// proj = p[0];
// }
//
// double[] projM = proj.cameraMatrix.get();
// double[] distort = proj.distortionCoeffs.get();
//
// OutputStream os = pa.createOutput(outputDAT);
//
// byte[] buf = new byte[SIZE_OF_PARAM_SET];
// ByteBuffer bb = ByteBuffer.wrap(buf);
// bb.order(ByteOrder.BIG_ENDIAN);
//
// bb.putInt(w);
// bb.putInt(h);
//
// //projection
// int k = 0;
// for (int j = 0; j < 3; j++) {
// for (int i = 0; i < 3; i++) {
// bb.putDouble(projM[k++]);
// }
// bb.putDouble(0);
// }
//
// //distortion
// for (int i = 0; i < 4; i++) {
// bb.putDouble(distort[i]);
// }
//
// os.write(buf);
// os.flush();
// os.close();
//
// pa.println("Conversion done !");
// return;
// }
}