Save photos of serial cam to hard disk

Hey people:

I've working with the arduino and a ttl cam (VCO 703) and I need to save the pictures to my computer -all the projects talk about save the pictures with a sd card, but I need to do it directly from the serial port to the computer-,I've been trying to do it writing the buffer of the picture to the serial port, but something is wrong because all that I see with the serial monitor are strange caracters, I'd appreciate if you can help me to know the way to save and see this type of data (jpg files) to the hard disk, the code that I've been editing is this:

#include <VC0706.h>
//#include <SD.h>
#if ARDUINO >= 100
#include <SoftwareSerial.h>
#else
#include <NewSoftSerial.h>
#endif

// This is the camera pin connection. Connect the camera TX
// to pin 4, camera RX to pin 5
#if ARDUINO >= 100
NewSoftSerial nss(4, 5);
#else
NewSoftSerial cameraconnection = NewSoftSerial(4, 5);
#endif
// pass the serial connection to the camera object
VC0706 cam = VC0706(&cameraconnection);

void setup() {
Serial.begin(38400);
Serial.println("VC0706 Camera test");

// Try to locate the camera
if (cam.begin()) {
Serial.println("Camera Found:");
} else {
Serial.println("No camera found?");
return;
}
// Print out the camera version information (optional)
char *reply = cam.getVersion();
if (reply == 0) {
Serial.print("Failed to get version");
} else {
Serial.println("-----------------");
Serial.print(reply);
Serial.println("-----------------");
}

// Set the picture size - you can choose one of 640x480, 320x240 or 160x120
// Remember that bigger pictures take longer to transmit!

//cam.setImageSize(VC0706_640x480); // biggest
cam.setImageSize(VC0706_320x240); // medium
//cam.setImageSize(VC0706_160x120); // small

// You can read the size back from the camera (optional, but maybe useful?)
uint8_t imgsize = cam.getImageSize();
Serial.print("Image size: ");
if (imgsize == VC0706_640x480) Serial.println("640x480");
if (imgsize == VC0706_320x240) Serial.println("320x240");
if (imgsize == VC0706_160x120) Serial.println("160x120");

// Motion detection system can alert you when the camera 'sees' motion!
cam.setMotionDetect(true); // turn it on
//cam.setMotionDetect(false); // turn it off (default)

// You can also verify whether motion detection is active!
cam.takePicture();

Serial.print("Motion detection is ");
if (cam.getMotionDetect())
Serial.println("ON");
else
Serial.println("OFF");
uint16_t jpglen = cam.frameLength();

Serial.print(jpglen, DEC);
Serial.println(" byte image");

while(jpglen !=0){
Serial.print(jpglen, DEC);
uint8_t *buffer;
uint8_t bytesToRead = min(64, jpglen);
buffer = cam.readPicture(bytesToRead);
Serial.write (buffer,bytesToRead); // Here I try to write the "image" data to the serial port

jpglen -= bytesToRead;

}

cam.resumeVideo();

Serial.print(jpglen, DEC);
Serial.println("byte image");

Serial.println("...Done!");

cam.setMotionDetect(true);

}

void loop () {
char filename[13];
strcpy(filename, "IMAGE00.JPG");
for (int i = 0; i < 100; i++) {
filename[5] = '0' + i/10;
filename[6] = '0' + i%10;
}

Serial.write(filename);
uint16_t jpglen = cam.frameLength();
Serial.print(jpglen, DEC);
Serial.println(" byte image");

Serial.print("Writing image to "); Serial.print(filename); // Here I pretend to write the name of the file to the serial port

}

all that I see with the serial monitor are strange caracters

Sounds like its working.

So what are you planning to receive the data with on the PC and write it to disk? A Python app? Processing app? Something else?

#if ARDUINO >= 100
 #include <SoftwareSerial.h>
#else
 #include <NewSoftSerial.h>
#endif

You are including the correct header file, based on the version of the IDE.

#if ARDUINO >= 100
NewSoftSerial nss(4, 5);
#else
NewSoftSerial cameraconnection = NewSoftSerial(4, 5);
#endif

NewSoftSerial should not be used with 1.0 or higher.

Why do you have different instance names?

I don't suppose it is necessary to ask which version of the IDE you are using, since you code won't actually compile on 1.0.

  Serial.begin(38400);

What are you talking to? That's a non-standard baud rate used only by MIDI devices.

Hey,

Well, I have to see the image in a Java Application or store the image and then open it through any image software, the 38400 is the standard speed that the serial camera manages and the valid instance is the cameraconection = NewSoftSerial (4,5), I added the nss because I was doing tests.

Ok so the strange characters you see in the serial monitor are what you would expect to see when you write binary data to the serial port like your sketch does here:

      Serial.write (buffer,bytesToRead); // Here I try to write the "image" data to the serial port

So seeing strange characters means your sketch is probably working.

The next step is to write some code to run on the PC to receive that data and, as you said, display it as a jpeg or write it to disk.

Yes Dhunt that's right, but I don't know the buffer size of the image and I don't know if I have to program an special line to the arduino to send the image data, because when I run java or the visual c (where I program the receive file software) it doesn't show anything, maybe the buffer is storing information that doesn't correspond to the picture

maybe the buffer is storing information that doesn't correspond to the picture

No, but you are sending picture data and a bunch of other junk to the serial port. If you are writing all that stuff to one file, it is no wonder the file does not represent a picture.

Do you know how to remove that segment of serial data that I don't need to show a coherent image ?, I forgot to say something, when I open my C# 2010 program, the media of the program only shows "empty file".

when I open my C# 2010 program

You appear to have 3 or more distinct problems. First, you are sending a bunch of stuff from the Arduino that you shouldn't be sending. // will take care of that.

Second, you seem to have some C# code that is collecting the data into a file, that you have not shown us, that appears not to be working.

Third, you have some C# code that is trying to use that data to display an image. You haven't shown us that code, either.

You really can't expect us to help you fix code we haven't seen.

Ok, thank you for the response, here is the visual c# 2010 two button program that open the serial port (COM 2) and pretends "to show the image":

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void serialPort2_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
List recibido = new List(); //byte receive

int bytes = serialPort2.BytesToRead;

byte[] buffer = new byte[bytes];

serialPort2.Read(buffer, 0, bytes);
foreach (byte elem in buffer)
{
recibido.Add(elem); //here "it receives the file"
}

}

private void button1_Click(object sender, EventArgs e)
{
List recibido = new List();
serialPort2.Open();
recibido.Clear();

}

private void button2_Click(object sender, EventArgs e) //with this button I pretend to show the image after the computer receive it.
{
List recibido = new List(); //list receive
serialPort2.Close();

//Guarda todo en archivo, here It suppose to save everything inside the archive
if (File.Exists("Prueba.jpg"))
File.Delete("Prueba.jpg");
FileStream archivoP = new FileStream("Prueba.jpg",
FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter escribirP = new BinaryWriter(archivoP);
foreach (byte elem in recibido)
{
escribirP.Write(elem);
}
escribirP.Close();
archivoP.Close();
Process.Start("Prueba.jpg");

}
}
}

But when open the Windows gallery, It says that is an empty file.

Why don't you add some debug prints to your C# code so you can see what you are receiving and if it makes sense for what you are doing with the received data.

        private void serialPort2_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

How have you defined that this method should be called? If this method is triggered as soon as ANY data arrives on the serial port, then the code in it is suspect.

            List<byte> recibido = new List<byte>(); //byte receive

Make an empty List.

            int bytes = serialPort2.BytesToRead;

The name is atrocious. It is not an array as implied. It is a count of the number of bytes that are available to read, which will certainly not equal the number of bytes in the picture.

            byte[] buffer = new byte[bytes];

Now, we create an array to hold the serial data.

            serialPort2.Read(buffer, 0, bytes);
            foreach (byte elem in buffer)
            {
                recibido.Add(elem); //here "it receives the file"
            }

Then, we read all the data that we knew about earlier (more may have arrived) from the serial port, storing the data in the array. Then, we loop, moving each character from the array to the list.

        }

Then, the function ends, and the list goes out of scope without ever having been persisted anywhere. So, all the serial data just read, valuable or not, just hit the bit bucket.

        private void button1_Click(object sender, EventArgs e)
        {
            List<byte> recibido = new List<byte>();
            serialPort2.Open();
            recibido.Clear();

        }

Create a List, close the serial port, clear the empty list, and let the empty, cleared list go out of scope. What was the purpose of the List?

        private void button2_Click(object sender, EventArgs e) //with this button I pretend to show the image after the computer receive it.
        {
            List<byte> recibido = new List<byte>(); //list receive
            serialPort2.Close();

            //Guarda todo en archivo, here It suppose to save everything inside the archive
            if (File.Exists("Prueba.jpg"))
                File.Delete("Prueba.jpg");
            FileStream archivoP = new FileStream("Prueba.jpg",
                FileMode.OpenOrCreate, FileAccess.Write);
            BinaryWriter escribirP = new BinaryWriter(archivoP);
            foreach (byte elem in recibido)
            {
                escribirP.Write(elem);
            }

Create a new, empty List. If the file exists, delete it. Then, open the file. Write the data in the empty list to the file, and close it. Then, try to display the empty picture, and wonder why the picture is empty.

Do you have a clue, now, how to fix your problem?

Hi People;

I modified the c #2010 code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void serialPort2_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) // It receives the data when I click the button

{
List recibido = new List();

int bytes = serialPort2.BytesToRead;

byte[] buffer = new byte[bytes];

serialPort2.Read(buffer, 0, bytes);
foreach (byte elem in buffer)
{
recibido.Add(elem);
}

}

private void button1_Click(object sender, EventArgs e)
{
List recibido = new List();
serialPort2.Open();
// recibido.Clear();

}

private void button2_Click(object sender, EventArgs e)
{
List recibido = new List();
//serialPort2.Close();
if (File.Exists("Pruebados.jpg")) ;
//Guarda todo en archivo
FileStream archivoP = new FileStream("Pruebados.jpg",
FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter escribirP = new BinaryWriter(archivoP);
foreach (byte elem in recibido)
{
escribirP.Write(elem);
}
//escribirP.Close();
//archivoP.Close();
Process.Start("Pruebados.jpg");
}
}
}

And I also modified the arduino code to send only the image data and once:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void serialPort2_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
List recibido = new List();

int bytes = serialPort2.BytesToRead;

byte[] buffer = new byte[bytes];

serialPort2.Read(buffer, 0, bytes);
foreach (byte elem in buffer)
{
recibido.Add(elem);
}

}

private void button1_Click(object sender, EventArgs e)
{
List recibido = new List();
serialPort2.Open();
// recibido.Clear();

}

private void button2_Click(object sender, EventArgs e)
{
List recibido = new List();
//serialPort2.Close();
if (File.Exists("Pruebados.jpg")) ;
//Guarda todo en archivo
FileStream archivoP = new FileStream("Pruebados.jpg",
FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter escribirP = new BinaryWriter(archivoP);
foreach (byte elem in recibido)
{
escribirP.Write(elem);
}
//escribirP.Close();
//archivoP.Close();
Process.Start("Pruebados.jpg");
}
}
}

When I run the C program; the arduino shield doesn't show the TX led transmitting, so I suppose that the program doesn't run correctly the serial port, because when I do the test with the VCO 706 Comm tool; the tx led runs, and starts to show the data (same happens with the serial monitor of the arduino soft):

FF D8 FF FE 00 24 59 00 5B 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 00 40 01 1B 00 32 12 0B 51 04 51 04 00 00 FF DB 00 84 00 07 05 05 06 05 04 07 06 05 06 08 07 07 08 0A 11 0B 0A 09 09 0A 14 0E 0F 0C 10 18 15 19 18 17 15 17 16 1A 1D 25 20 1A 1C 23 1C 16 17 21 2C 21 23 27 28 2A 2A 2A 19 1F 2E 31 2E 29 31 25 29 2A 28 01 07 07 (.....more and more hexa caracters........)77 37 F1 7E 55 71 87 73 29 4C 6F 96 07 6A 5D B5 64 5C 4D B4 9B B6 93 6D 2D 80 42 B4 D2

I appreciate your help.

I don't think that that "Arduino code" will actually compile for the Arduino.

The C# code is still wrong. All serial data received still ends up in the bit bucket.

Oh sorry, here you have the arduino code that I compiled to transmit the image data once.

#include <SoftwareSerial.h>
#include <NewSoftSerial.h>
#include <VC0706.h>

int incomingbyte=0;

NewSoftSerial cameraconnection = NewSoftSerial(2, 3);
VC0706 cam = VC0706(&cameraconnection);

void setup () {

Serial.begin(9600);
if (cam.begin()) {
cam.takePicture() ;
}
delay(3000);
uint16_t jpglen = cam.frameLength();
// Serial.print(jpglen, DEC);
// Serial.println(" byte image");

while (jpglen != 0) {
// read 64 bytes at a time;
uint8_t *buffer;
uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
buffer = cam.readPicture(bytesToRead);
Serial.write(buffer, bytesToRead);
//Serial.print("Read "); Serial.print(bytesToRead, DEC); Serial.println(" bytes");
jpglen -= bytesToRead;
}

}

void loop (){

}

PaulS:
I don't think that that "Arduino code" will actually compile for the Arduino.

The C# code is still wrong. All serial data received still ends up in the bit bucket.

Feelin' like a dentist yet...? :wink: