3d scanner with Arduino and laser pointer

here:

I made something for you.

As I described above the steps.

  • ArrayList listOfFrames holds the steps of your scans.
  • Each frame / scan holds several points. Here you have to implement your scan.
  • in state 0 you can loop through the points (space bar)
  • Press return now
  • in state 1 the points are connected to the 3D form using a circle form (aka cylinder). This is the core idea. That’s how you can go from 2D (points) to 3D points deforming/making a cylinder.
  • Look at it with peasyCam

Chrisir

import peasy.*;

final int  show2D=0;
final int  show3D=1;
int state=show2D; 

PeasyCam camera;

ArrayList<Frame> listOfFrames = new ArrayList();
ArrayList<OneQuad> listOneQuad = new ArrayList(); 

// Tool classes 
ToolsPVector toolsPVector = new ToolsPVector();

// float a3=0; 

int i_key=0; 

// ---------------------------------------------------------------

void setup() {
  size(1300, 990, P3D);

  camera = new PeasyCam(this, width/2, height/2, 0, 900);

  createArrayList();
  make3DShape();
} //func setup()

void draw() {

  switch(state) {

  case show2D:
    background(0); // black
    camera(); 

    Frame cf=listOfFrames.get(i_key); // for (Frame cf : listOfFrames) {
    cf.display(300);
    fill(255);
    text("Space Bar to show next frame; ENTER to go to 3D mode; showing frame "
      + i_key 
      +" of "
      +listOfFrames.size()
      +".", 
      19, 19); 
    break; 

  case show3D:
    background(111); // gray 

    avoidClipping(); 
    ambientLight(128, 128, 128) ;
    directionalLight(128, 128, 128, 
      0, 0, 1);
    directionalLight(128, 128, 128, 
      0, 0, -1);
    lightFalloff(1, 0, 0);
    lightSpecular(0, 0, 0);

    // --------

    CheckeredFloor(); 

    for ( OneQuad current : listOneQuad ) {
      current.display();
    }
    break; 

  default : 
    println("Error in draw()"); 
    exit(); 
    break;
  }//switch
  //
} // func draw()

// ---------------------------------------------------------------------------------------------------------------------
// Inputs 

void keyPressed() {

  if (key==' ') {
    i_key++; 
    if (i_key>=listOfFrames.size()) {
      //i_key=listOfFrames.size()-1;
      i_key=0;
    }
  } else if (key==RETURN || key==ENTER) {
    state = show3D;
    i_key=0;
  }
  //
}//func

// ---------------------------------------------------------------------------------------------------------------------
// creating Data

void createArrayList() {
  // create frames 
  ArrayList<Frame> listOfFramesHelper = new ArrayList(); 

  Frame newF = new Frame(); 
  newF.listOfCells.add(new Cell(width/2, 100)); 
  newF.listOfCells.add(new Cell(width/2-210, 200)); 
  newF.listOfCells.add(new Cell(width/2-300, 300)); 
  newF.listOfCells.add(new Cell(width/2-20, 400)); 
  listOfFramesHelper.add(newF); 

  newF = new Frame(); 
  newF.listOfCells.add(new Cell(width/2, 100)); 
  newF.listOfCells.add(new Cell(width/2-110, 200)); 
  newF.listOfCells.add(new Cell(width/2-400, 300)); 
  newF.listOfCells.add(new Cell(width/2-40, 400)); 
  listOfFramesHelper.add(newF); 

  newF = new Frame(); 
  newF.listOfCells.add(new Cell(width/2, 100)); 
  newF.listOfCells.add(new Cell(width/2-130, 200)); 
  newF.listOfCells.add(new Cell(width/2-400, 300)); 
  newF.listOfCells.add(new Cell(width/2-330, 400)); 
  listOfFramesHelper.add(newF); 

  // ------------------------------------------------

  // interpolate ---

  for (int i=0; i<listOfFramesHelper.size()-1; i++) {

    Frame f1=listOfFramesHelper.get(i); 
    Frame f2=listOfFramesHelper.get(i+1); 

    for (int i2=0; i2<10; i2++) { // 10 is the resolution

      newF = new Frame(); 

      for (int i3=0; i3<f1.listOfCells.size(); i3++) {

        Cell c1=f1.listOfCells.get(i3); 
        Cell c2=f2.listOfCells.get(i3); 

        float x1 = lerp( c1.x, c2.x, i2 / 10.0 ); 
        float y1 = lerp( c1.y, c2.y, i2 / 10.0  ); 

        newF.listOfCells.add(new Cell(x1, y1));
      }//for
      listOfFrames.add(newF);
    }//for
  }//for

  // interpolate between last and first ---

  Frame f1=listOfFramesHelper.get(listOfFramesHelper.size()-1); 
  Frame f2=listOfFramesHelper.get(0); 

  for (int i2=0; i2<10; i2++) { // 10 is the resolution

    newF = new Frame(); 

    for (int i3=0; i3<f1.listOfCells.size(); i3++) {

      Cell c1=f1.listOfCells.get(i3); 
      Cell c2=f2.listOfCells.get(i3); 

      float x1 = lerp( c1.x, c2.x, i2 / 10.0 ); 
      float y1 = lerp( c1.y, c2.y, i2 / 10.0  ); 

      newF.listOfCells.add(new Cell(x1, y1));
    }//for
    listOfFrames.add(newF);
  }//for
  println(listOfFrames.size());
}//func 

// -- -- -- -- -- -- 

void make3DShape() {

  // The Core Function 

  for (int i=0; i<listOfFrames.size()-1; i++) {

    float angle = map (i, 0, listOfFrames.size(), 0, TWO_PI);  
    float angle2 = map (i+1, 0, listOfFrames.size(), 0, TWO_PI);  

    Frame f1=listOfFrames.get(i);   
    Frame f2=listOfFrames.get(i+1); 

    for (int i3=0; i3<f1.listOfCells.size()-1; i3++) {

      Cell c1=f1.listOfCells.get(i3); // upper left corner 
      Cell c2=f2.listOfCells.get(i3); // upper right 

      Cell c3=f1.listOfCells.get(i3+1);  // lower left 
      Cell c4=f2.listOfCells.get(i3+1);  // lower right 

      //---
      float x1 = cos(angle) * (width/2-c1.x); // same corners as above 
      float y1 = c1.y; 
      float z1 = sin(angle) * (width/2-c1.x) +0; 

      float x2 = cos(angle2) * (width/2-c2.x); 
      float y2 = c2.y; 
      float z2 = sin(angle2) * (width/2-c2.x) +0;

      float x3 = cos(angle) * (width/2-c3.x); 
      float y3 = c3.y; 
      float z3 = sin(angle) * (width/2-c3.x) +0; 

      float x4 = cos(angle2) * (width/2-c4.x); 
      float y4 = c4.y; 
      float z4 = sin(angle2) * (width/2-c4.x) +0;

      OneQuad newOneQuad = new OneQuad ( 
        new PVector ( x1, y1, z1 ), 
        new PVector ( x2, y2, z2 ), 
        new PVector ( x4, y4, z4 ), // changed order here 
        new PVector ( x3, y3, z3 )
        );  

      listOneQuad.add(newOneQuad);
    }//for
    //
  }//for

  //---------------------------------------
  // close shape

  float angle = map (listOfFrames.size()-1, 0, listOfFrames.size(), 0, TWO_PI);  
  float angle2 = map (0, 0, listOfFrames.size(), 0, TWO_PI);  

  Frame f1=listOfFrames.get(listOfFrames.size()-1);   
  Frame f2=listOfFrames.get(0); 

  for (int i3=0; i3<f1.listOfCells.size()-1; i3++) {

    Cell c1=f1.listOfCells.get(i3); // upper left corner 
    Cell c2=f2.listOfCells.get(i3); // upper right 

    Cell c3=f1.listOfCells.get(i3+1);  // lower left 
    Cell c4=f2.listOfCells.get(i3+1);  // lower right 

    //---
    float x1 = cos(angle) * (width/2-c1.x); // same corners as above 
    float y1 = c1.y; 
    float z1 = sin(angle) * (width/2-c1.x) +0; 

    float x2 = cos(angle2) * (width/2-c2.x); 
    float y2 = c2.y; 
    float z2 = sin(angle2) * (width/2-c2.x) +0;

    float x3 = cos(angle) * (width/2-c3.x); 
    float y3 = c3.y; 
    float z3 = sin(angle) * (width/2-c3.x) +0; 

    float x4 = cos(angle2) * (width/2-c4.x); 
    float y4 = c4.y; 
    float z4 = sin(angle2) * (width/2-c4.x) +0;

    OneQuad newOneQuad = new OneQuad ( 
      new PVector ( x1, y1, z1 ), 
      new PVector ( x2, y2, z2 ), 
      new PVector ( x4, y4, z4 ), // changed order here 
      new PVector ( x3, y3, z3 )
      );  

    listOneQuad.add(newOneQuad);
  }//for

  // -------------------------

  println( listOneQuad.size());
}//func 

//-----------------------------------------------------------------------------
// floor

void CheckeredFloor() {
  //floor

  noStroke(); 

  for (int i = -40; i < 40; i++) {
    for (int j = -40; j < 40; j++) {

      // get color
      // % is modulo, meaning rest of division 
      if (i%2 == 0) { 
        if (j%2 == 0) { 
          fill (255, 0, 0);
        } else 
        {
          fill ( 103 );
        }
      } else {
        if (j%2 == 0) { 
          fill ( 103 );
        } else 
        {
          fill (255, 0, 0);
        }
      } // if

      pushMatrix(); 
      translate ( 80*i, height/2+210+30+3.5, 80*j ); 
      box ( 80, 7, 80); // one cell / tile 
      popMatrix();
    } // for
  } // for
} // function 

//-----------------------------------------------------------------------------------------------
// Tools 

void avoidClipping() {
  // avoid clipping (at camera): 
  // https : // 
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func 

// ==============================================================================================

class Frame {
  // 2D

  // one frame holds a list of points from the image scan

  ArrayList<Cell> listOfCells = new ArrayList(); 

  void display(float xpos) {
    stroke(255); 
    for (Cell c1 : listOfCells) {
      fill(i_key*49+60, 0, 0); 
      ellipse(c1.x+xpos, c1.y, 
        6, 6);
    }
  }
}//class

// ==============================================================================================

class OneQuad {
  // 3D surface (rect)
  PVector pv0, pv1, pv2, pv3; 

  // constr
  OneQuad (PVector pv0_, PVector pv1_, PVector pv2_, PVector pv3_) {
    pv0=pv0_.copy();
    pv1=pv1_.copy();
    pv2=pv2_.copy();
    pv3=pv3_.copy();
  }// constr

  void display() {

    fill(255, 0, 0);

    beginShape(QUAD); // //class 

    fill(255, 0, 0); 
    vertex(pv0.x, pv0.y, pv0.z);
    vertex(pv1.x, pv1.y, pv1.z);
    vertex(pv2.x, pv2.y, pv2.z);
    vertex(pv3.x, pv3.y, pv3.z);

    endShape(CLOSE); // CLOSE
  }
}//class

// ==============================================================================================

class Cell {

  float x, y; // pos
  int sclx=1, scly=1; // size 

  //  int i, j; // pos in grid (col/row)

  boolean state=false; // ON / OFF

  // Two colors 
  color colorForOff=  color(random(255), random(255), random(255)); // color(0); // 
  color colorForON=color((255), 0, 0); 

  String strImgName  = ""; 
  PImage imgCell  = null; 

  //constr 
  Cell(float x_, float y_) {
    x = x_; 
    y = y_;
  }  //constr 

  void display() {
    fill( colorForOff ); 
    stroke(111); 

    rect(x, y, 
      sclx, scly);
  }//func 

  String toString() {
    return str(x)
      +","+
      str(y);
  }
  //
}//class

//===================================================================================

class ToolsPVector {

  // not a class for an object like a car but a class that collects Tools - FOR 3D -----------!!!! 

  void linePV ( PVector pv1, PVector pv2) {
    line(pv1.x, pv1.y, pv1.z, 
      pv2.x, pv2.y, pv2.z);
  }//func

  void pointPV ( PVector pv) {
    point(pv.x, pv.y, pv.z);
  }//func

  void spherePV ( PVector pv) {
    pushMatrix(); 
    translate(pv.x, pv.y, pv.z); 
    noStroke(); 
    fill(255, 0, 0); 
    sphere(17); 
    popMatrix();
  }//func

  void spherePVCol ( PVector pv, color c1) {
    pushMatrix(); 
    translate(pv.x, pv.y, pv.z); 
    noStroke(); 
    fill(c1); 
    sphere(17); 
    popMatrix();
  }//func

  void vertexPV(color col_, PVector pv_) {
    fill(col_); 
    vertex(pv_.x, pv_.y, pv_.z);
  }
  //
}//class
//

1 Like

thanks a lot i am working on your steps

@paulgoux hi

i do have this part of code how to replace it using ketai library can ketai works instead of video library?


import processing.video.*;
import nervoussystem.obj.*;
import processing.serial.*;
Capture cam ;
Serial myPort;


void setup() {
  size(800, 600);
  
 
  
    cam = new Capture(this, 640, 480);
    cam.start();
  }

i try to follow this code but could not

Open Android Camera

Dont forget ketai import.

import android.os.Environment;
import android.os.Build ;
import android.app.Activity;
import android.content.Context;

boolean k1 = false;
int W = 1440, H = 720;
Permission storage, camera, readStorage;
PGraphics canvas;
PShader edges;
KetaiCamera cam;

//void settings(){
//  //size(W,H,P2D);
//};


void setup() {
  fullScreen(P2D);
  orientation(LANDSCAPE);
  cam = new KetaiCamera(this, width, height, 60);
  canvas = createGraphics(width, height, P2D);
  //edges = loadShader("edges.glsl");
  storage = new Permission(this, "WRITE_EXTERNAL_STORAGE");
  readStorage = new Permission(this, "READ_EXTERNAL_STORAGE");
  camera = new Permission(this, "CAMERA");
  //cam.start();
};

void draw() {
  fill(255);
  background(0);
  if (frameCount>10&&!cam.isStarted())cam.start();
  image(cam, 0,0);
  text(frameRate, 50, 100);
};

void mousePressed() {
  //if (cam.isStarted()){
  //  cam.stop();
  //}else cam.start();

  if (cam.isFlashEnabled())
    cam.disableFlash();
  else
    cam.enableFlash();
};

void onCameraPreviewEvent() {
  cam.read();
};


public class Permission{
  
  PApplet parent;
  String p;
  
  public boolean requestedPortraitImage = false;

  public Permission(PApplet pParent,String permissionName) {
    parent = pParent;
    p = permissionName;
    parent.requestPermission("android.permission."+permissionName, "onPermissionResult", this);
    println(permissionName);
  };

  public void onPermissionResult(boolean granted) {
    if (!granted) {
      PApplet.println("User did not grant ",p, "permission. Camera is disabled.");
    }
  };

};

as a class

import android.os.Environment;
import android.os.Build ;
import android.app.Activity;
import android.content.Context;

boolean k1 = false;
AndroidCamera cam;

void setup() {
  fullScreen(P2D);
  orientation(LANDSCAPE);
  cam = new AndroidCamera(this, width, height, 60);
};

void draw() {
  fill(255);
  background(0);
  cam.display();
};



void mousePressed() {
  cam.toggleFlash();
};

void onCameraPreviewEvent() {
  cam.read();
};

class AndroidCamera {
  PApplet applet;
  KetaiCamera cam;
  int w, h;
  Permission storage, camera, readStorage, P;
  PGraphics canvas;
  PShader shader;
  
  AndroidCamera(PApplet p, int w, int h, int frate) {
    this.w = w;
    this.h = h;
    applet = p;
    cam = new KetaiCamera(p, w, h, frate);
    P = new Permission(p, "WRITE_EXTERNAL_STORAGE");
    P = new Permission(p, "READ_EXTERNAL_STORAGE");
    P = new Permission(p, "CAMERA");
    canvas = p.createGraphics(w, h, P2D);
  };

  void display() {
    start();
    canvas.beginDraw();

    //mult = BMS.Sliders.get(0).value;
    //counter = BMS.Sliders.get(1).value;
    //mult = 1.0;
    //counter = 1.0;
    //edges.set("mult",mult);
    //edges.set("type",counter);
    if (shader!=null)canvas.shader(shader);
    canvas.image(cam, 0, 0);
    canvas.text(frameRate, 50, 100);
    applet.image(canvas, 0, 0);
    //canvas.imageMode(CORNER);
    //canvas.fill(0);
    //canvas.rect(0, 0, width, 20);
    canvas.endDraw();
  };

  void start() {
    if (applet.frameCount>10&&!cam.isStarted())cam.start();
  };

  void toggleFlash() {
    if (cam.isStarted()) {
      if (cam.isFlashEnabled())
        cam.disableFlash();
      else
        cam.enableFlash();
    }
  };

  void read() {
    cam.read();
  };
};

@jafal

did this work for you?

@paulgoux hi

i was working with hardware of the scanner it is need more calibration to get more reasonable result and reliability

next stage i am going to move to android mode i want to replace the video library with ketai camera

this is some scanned stuff



Ok… doesnt answer the question…

@paulgoux

it is fine so far i did not implement the whole code i just used part of it but its useful and thanks for you

1 Like

how to chose the saving folder destination after compiling i mean making the application afford you choice where to save … how to do it ?

The filewriter library ive created has that functionality, you initialise it, then tell it what type of file you are saving, inage text etc, default is txt if none is set. Then you set the write location and stipulate wether you want to create the file if the destination folder does not have the desired file. If the file is found you check if you want to overwrite the file or created a new numbered file again the library habndles numbering.

You can then append or overwrite the file deoending on your needs.

Ill also add the option to append the folder later.

If you dont want to use the lib ive left the standalone class in the gallery section.

Also the lib version has dialogue boxes and textboxes. A textbox to set the desired location if you dont know where you want to save at runtime and a dialogue box to get the user overwrite/append choice.

the sketch i am using deals with image and txt at the same time saving pics to folder and recall them for analyzing then save them a gain

Then thats also doable for the library. You could just create two instances of the file output. One to handle the image and the other to handle the text, otherwise you would need to reset all the check bools in between switching types, as the set location function determines what operations to perform

i am going to try it thank you

Note that the github version hasnt been updated with the latest stable version so may have some issues.

i see

i am now working with replacing video library with ketai then moving afterword for saving stuff

heres a simple image save class and sketch

class imageSaver{
  Permission wstorage,rstorage;
  Activity act;
  PApplet p;
  int counter = -1,maxImageCount;
  boolean imageSaved,mdown;
  String folderName = "MyImageFolder",fileName,ext,absolutePath;
  String imageFile = "MyImage.jpg";
  PImage img;
  File file,file2;
  
  imageSaver(PApplet applet){
    p = applet;
    wstorage = new Permission(p,"WRITE_EXTERNAL_STORAGE");
    act = p.getActivity();
    getExt(imageFile);
  };
  
  imageSaver(PApplet applet,String s1, String s2){
    folderName = s1;
    imageFile = s2;
    p = applet;
    wstorage = new Permission(p,"WRITE_EXTERNAL_STORAGE");
    act = p.getActivity();
    getExt(imageFile);
  };
  
  public void logic() {
    if(mousePressed&&!mdown) {
      img = p.get();
      checkLocation(folderName, imageFile);
      mdown = true;
      counter++;
    }
    if(!mousePressed)mdown = false;
  };

  public void logic(PGraphics canvas) {
    if(true) {
      
      img = canvas.get();
      checkLocation(folderName, imageFile);
      counter++;
    }
  };


  public void checkLocation(String sf, String tf) { 
    boolean k = false;
    try { 
      absolutePath = new String(Environment.getExternalStorageDirectory().getAbsolutePath()); 
      file = new File(absolutePath+"/"+sf); 
      //PApplet.println("checking file1",file,counter);
      if (!file.exists()&&counter==-1) { 
        boolean success = true; 
        success = file.mkdirs();
        img.save(file+"/"+fileName+"."+ext);
        
      } else k = true;
      
      if(counter>-1)k=true;
      boolean k1 = false;
      while(k&&counter<100&&!k1) {
        try { 
          file2 = new File(absolutePath+"/"+folderName+"/"+fileName+counter+"."+ext); 
          PApplet.println("checking file2",file2);
          if (file2.exists()) { 
            counter++;
          } else {
            k = false;
            k1 = true;
            break;
          }
        } 
        catch (Exception e) { 
          PApplet.println("Error while saving file: " + e);
        }
      }
      if(k1){
        //PApplet.println("file",file);
        //PApplet.println("Fname",folderName);
        //PApplet.println("fileName",fileName);
        //PApplet.println("counter",counter);
        //PApplet.println("ext",ext);
        if(counter>-1)img.save(file+"/"+fileName+counter+"."+ext);
        imageSaved = true;
        //PApplet.println("File saved successfully.");
      }
    } 
    catch (Exception e) { 
      PApplet.println("Error while saving file: " + e);
    }
  };
  
  void getExt(String location){

    int count = 0;
    fileName = location.substring(0,location.indexOf("."));
    ext = location.replace(fileName,"");
    ext = ext.replace(".","");
    ext = ext.replace(fileName,"");
  };
  
  public File[] listFiles(String dir) {
    File file = new File(dir);
    if (file.isDirectory()) {
      File[] files = file.listFiles();
      return files;
    } else {
      // If it's not a directory
      return null;
    }
  };

};

import android.os.Environment;
import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Build.VERSION_CODES; 

import android.app.Activity; 
imageSaver img;

void setup(){
  size(displayWidth, displayHeight);
  background(0, 0, 200); 
  rectMode(CENTER);
  rect(width/2, height/2, width, height/2);
  textAlign(CENTER);
  String str = "Click to save an image.";
  textSize(12);
  float twf = width/textWidth(str);
  textSize(8*twf);
  fill(0);
  text(str, width/2, height/2);
  img = new imageSaver(this);
};

void draw(){
  img.logic();
};

thank you i was reading this now

Filewriter for Android

1 Like

@paulgoux is there working video library for APDE ?

Does ketai not work?

i am still modify the code did not finished yet but am asking if there is video library for android