Another Serial/Arduino Project.
Hope someone find use for it.
Taking a series of pictures with a camera, you can build a 3d Model with that photo's.
I use 3DSom for the photo manipulation, but I'm sure there is other software available.
Then the model can be edited in Blender, or your faviorite 3d Modeling Software.
The model rendering will be as good as your Masking of the Images, which can take some time.
The Arduino is use to turn the model around 360 degrees, and AppGameKit take care of snapping photo's with an interval, Pause the Process, adjust the camera etc...
This is more of an fun project / proof of concept to see if it will work , and actually surprise me with a very good result with not much effort.
If I spend more time masking my image, results will be even better, but I let the program do it's thing (Almost everything Automated)
This is basic working code... Lots of possibilties to expand this 3D Photo scanner.... maybe one day when I'm bored again....
Parts Needed:
USB Camera
Arduino Uno, Nano, Mega etc
Stepper motor and A4988 Stepper Driver. Arduino Code bases on a Simple A4988, Other steppers can work with minimum changes
Genral Tools, Wires, power Supply
Arduino Diagram:
Arduino Code
/* Stepper Control / APPGAmekit / 3D Scanner
*
* by Danie de Beer
*
*/
// defines pins numbers
const int stepPin = 7;
const int dirPin = 8;
String inputString = ""; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
int multiplier = 20;
void setup() {
// Sets the two pins as Outputs
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
Serial.begin(115200);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
}
void loop() {
serialEvent();
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}
void serialEvent() {
while (Serial.available()) {
//Serial.println("SerialRecv");
// get the new byte:
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {
stringComplete = true;
if (inputString.charAt(0) == 'F') {
int a = inputString.charAt(1) -'0';
int b = inputString.charAt(2) -'0';
int c = inputString.charAt(3) -'0';
String d = String(a) + String(b) + String(c);
Serial.println(d);
int steps = d.toInt();
forwardStep(steps);
}
if (inputString.charAt(0) == 'B') {
int a = inputString.charAt(1) -'0';
int b = inputString.charAt(2) -'0';
int c = inputString.charAt(3) -'0';
b = b * 10;
c = c * 100;
int steps = a + b + c;
backStep(steps);
}
}
}
}
void forwardStep(int s){
digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction
// Makes 200 pulses for making one full cycle rotation
for(int x = 0; x < s*multiplier; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(500);
digitalWrite(stepPin,LOW);
delayMicroseconds(500);
}
}
void backStep(int s){
digitalWrite(dirPin,LOW); //Changes the rotations direction
// Makes 400 pulses for making two full cycle rotation
for(int x = 0; x < s*multiplier; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(500);
digitalWrite(stepPin,LOW);
delayMicroseconds(500);
}
}
AGK Code
#import_plugin SerialPlugin as serial
SetErrorMode(2)
// Project: arduino_agl_serial_plugin_Example1
// set window properties
SetWindowTitle( "3dCameraScanner" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
#include "main.scene"
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 )
cameraidswitch as integer
numcamera as integer
numcamera = GetNumDeviceCameras()
global scrollx as integer[10]
global scrolly as integer[10]
global scrollw as integer[10]
global scrollh as integer[10]
global scrollsprv as integer[10]
global scrollsprh as integer[10]
global scrolltext as integer[10]
global scrollval as integer[10]
global scrollvaltext as string[10]
global scrollmin as integer[10]
global scrollmax as integer[10]
main_setup()
global img as Integer = 9999
global cam as integer
global spr as integer
global countimg as integer = 1
cam=0
global instanceID as integer
global prevSprId as integer[100]
global PrevTextId as integer[100]
global prevsprites as integer[5]
global currentImgID as integer =5
global PrevImgCount as integer = 1
global img_leftbtnID as integer
global img_rightbtnID as integer
global img_dummy as integer
global img_imgbc_btn as integer
global img_imgfw_btn as integer
global resetnumber as integer = 1
global img_resetoff as integer
global img_reseton as integer
img_dummy = LoadImage( "dummy.png" )
img_imgbc_btn = LoadImage( "imgbc_btn.png" )
img_imgfw_btn = LoadImage( "imgfw_btn.png" )
img_leftbtnID = createsprite(img_imgbc_btn)
img_rightbtnID = createsprite(img_imgfw_btn)
img_resetoff = LoadImage( "resetoff.png" )
img_reseton = LoadImage( "reseton.png" )
for a = 1 to 5
prevsprites[a] = createsprite(img_dummy)
next a
for a = 1 to 100
prevtextId[a] = createtext(str(a))
settextsize(prevtextId[a],20)
settextposition(prevtextId[a],-1000,550)
next a
SetDeviceCameraToImage(cam,img) //cam input goto image, image for id will created
spr=CreateSprite(img) //image output into a sprite
setspritesize(spr,800,480) //full size
setspriteposition(spr,10,10)
global img_bar as integer
global img_vbar as integer
img_bar = LoadImage( "bar.png" )
img_vbar = LoadImage( "vbar.png" )
xx = 40
global ports as integer[4]
global portsname as string[4]
global portindex as integer
global Steps1Val as integer = 9
global Steps2Val as integer = 9
global auto as integer
global autorounds as integer = 1
global viewerlines as integer
global start as integer
global max as integer
global stp as integer
global nextphoto as integer
global maxphoto as integer
//Check if there is any available Comports
//If no Comports found, the APP will Exit
num = serial.EnumerateSerialPorts()
instanceID = serial.OpenSerialPort( instanceID, 115200, 1, 0 )
if num > 0
Print("Number of Ports Detected: "+str(num))
if GetFileExists("portnum.txt")
f = opentoread("portnum.txt")
portindex = val(readstring(f))
closefile(f)
else
f = opentowrite("portnum.txt")
writestring(f,"0")
closefile(f)
endif
temp$ = ""
for a = 0 to num-1
if portindex = a
temp$ = temp$+ str(a)+". Port "+serial.GetSerialPortName( a )+" >> USE" +chr(13)+chr(10)
else
temp$ = temp$+ str(a)+". Port "+serial.GetSerialPortName( a )+chr(13)+chr(10)
endif
next a
// message(temp$+chr(13)+chr(10)+"Baudrate = 115200"+chr(13)+chr(10)+"Change the file 'portnum.txt' to use other port")
global serialstring_eb as integer
global serialstring
for a = 1 to 5
if a = 1
setspriteposition(prevsprites[a],60,500)
SetSpritePosition(img_leftbtnID,getspritex(prevsprites[a])-getspritewidth(img_leftbtnID)-5,500)
else
setspriteposition(prevsprites[a],getspritex(prevsprites[a-1])+getspritewidth(prevsprites[a-1])+30,500)
endif
next a
SetSpritePosition(img_rightbtnID,getspritex(prevsprites[5])+getspritewidth(prevsprites[5])+5,500)
do
if start = 1
TakeAutoPhoto()
endif
spritehit = getspritehit(getpointerx(), getpointery())
if getpointerpressed()
if spritehit = img_rightbtnID
if PrevImgCount > 5
inc currentImgID
if currentImgID > PrevImgCount
currentImgID = PrevImgCount
else
for a = currentImgID-5 to currentImgID
if a = currentImgID-5
setspriteposition(prevSprId[a],60,500)
//SetSpritePosition(img_leftbtnID,getspritex(prevSprId[a])-getspritewidth(img_leftbtnID)-5,500)
else
setspriteposition(prevSprId[a],getspritex(prevSprId[a-1])+getspritewidth(prevSprId[a-1])+30,500)
endif
next a
endif
endif
elseif spritehit = main_resetnumber
if resetnumber = 1
resetnumber = 0
SetSpriteImage(main_resetnumber,img_resetoff)
else
SetSpriteImage(main_resetnumber,img_reseton)
resetnumber = 1
endif
endif
endif
if getvirtualbuttonpressed(main_auto_vb) = 1
Message("Get Ready and Press OK")
PrevImgCount=1
start = 1
if resetnumber = 1
clearPhotoRoll()
endif
nextphoto=0
max = val(GetEditBoxText(main_MaxSteps))
stp = val(GetEditBoxText(main_Steps_eb))
maxphoto = max/stp
resettimer()
endif
//Print(PrevImgCount)
if GetVirtualButtonPressed(main_ManuallyTakePhoto) = 1
SaveImage(img,"file"+str(countimg)+".png")
movePhotos(PrevImgCount)
inc PrevImgCount
inc countimg
elseif GetVirtualButtonPressed(main_Stepper_fwd) = 1
serial.WriteSerialData( instanceID, 'F'+GetEditBoxText(main_Steps_eb)+'\r\n', -1 )
elseif GetVirtualButtonPressed(main_Stepper_back) = 1
serial.WriteSerialData( instanceID, 'B'+GetEditBoxText(main_Steps_eb)+'\r\n', -1 )
endif
sync()
Loop
else
// No Ports detected, EXIT Program
Message("No Serial Port detect")
do
Exit
Loop
endif
function TakeAutoPhoto()
if timer() < val(geteditboxtext(main_delay_photo))
settextstring(main_temp_text,"waiting....")
else
inc nextphoto
if nextphoto <= maxphoto
SaveImage(img,"file"+str(PrevImgCount)+".png")
movePhotos(PrevImgCount)
inc PrevImgCount
settextstring(main_temp_text,"Photos..." + str(PrevImgCount))
serial.WriteSerialData( instanceID, 'F'+GetEditBoxText(main_Steps_eb)+'\r\n', -1 )
resettimer()
else
start=0
settextstring(main_temp_text,"Photos Total: " + str(PrevImgCount-1))
message("DONE")
endif
endif
endfunction
function MovePhotos(p)
if p < 6
for a = 1 to p
setspriteimage(prevsprites[a],loadimage("file"+str(p)+".png"))
SetTextposition(PrevTextId[p],getspritex(prevsprites[p]),getspritey(prevsprites[p])+GetSpriteHeight(prevsprites[p])+10)
next a
else
aa=1
//message(str(p))
for a = p-5 to p-1
//message(str(a))
setspriteimage(prevsprites[aa],loadimage("file"+str(a)+".png"))
settextstring(PrevTextId[aa],str(a))
SetTextposition(PrevTextId[aa],getspritex(prevsprites[aa]),getspritey(prevsprites[aa])+GetSpriteHeight(prevsprites[aa])+10)
inc aa
next a
endif
endfunction
function clearPhotoRoll()
for a = 1 to 5
setspriteimage(prevsprites[a],img_dummy)
next a
endfunction
Enjoy...
Danie