Fatest Way to Take Pictures and Transfer to Computer

Dear,

I am working on a real time system. I am trying to transfer images from the camera module to my laptop. I have already written code that transfer pictures from the device to my laptop using the built in webserver via wifi. However, I am only getting one picture every 4 seconds. Any suggestions to make this process faster , meaning 2 images (320X240 pixels) per second?
I have a spider I, wifi Rs21 module, camera module.

Thanks in advance

@ cyberh0me - The picture is actually around 320X240X3 ~= 230 KB . Is there any other way I can send more than two pictures per second? If this cant happen with current used devices I mentioned in my post, please suggest any proper devices to do so.

Thanks in advance

@ welmanna@ my.bridgeport.edu - there are several steps involved in the process you described. to improve the performance, assuming it is possible, you need to understand the performance characteristics of each step.

is it the speed at which the camera takes an image? is it when the image is prepared for transmission? is the wifi transfer the bottleneck?

you need to add code to each step, to determine where there is are performance issue(s).

btw, i believe an image uses four bytes per pixel not three.

@ welmanna@ my.bridgeport.edu -

Is that serial camera or USB camera module?

Usually 320x240 jpg just take 10-15KB (normal quality) so you can send more than 2.

If I remember correctly camera should take image in jpg mode, meaning you can send raw JPG data instead of converting to bitmap before sending.

After received raw jpg data, let PC convert to bitmap if bitmap needed.

No IP camera using bitmap images to transfer over internet, I believe.

@ Mike,@ Dat - I believe the camera is capable of taking 20fps on smaller resolutions and is also capable of taking 2 or more frames per second on the max resolution of 320240. The camera module is this one([url]https://www.ghielectronics.com/catalog/product/283[/url]). I think the bottle neck is the web server which responds with the image byte array. I have been sending one picture as 3202403 byte array. On average it takes 4-5 secs when I send two images((320240*3)*2) at once. The code below is what i have been using on the device.I have also posted my client code which makes a request to server every 5 seconds. Any suggestions on how to make it faster is appreciated.


using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Net.NetworkInformation;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using System.Threading;

namespace Test123
{
    public partial class Program
    {
        private string webServerIpAddress = string.Empty;
        byte[] buff;
        byte[] buff1;
        byte[] buff2;
        int count = 0;
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted ( )
        {
            NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged; // event listener when wifi network is available
            NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged; // event listener when device gets ip address
            camera.CameraConnected += this.camera_CameraConnected;
            camera.BitmapStreamed += this.camera_BitmapStreamed; // event listener every time a picture is taken

            if (!wifiRS21.NetworkInterface.Opened)
            {
                Debug.Print("open");
                wifiRS21.NetworkInterface.Open();
            }
            if (wifiRS21.NetworkInterface.Opened)
            {
                if (!wifiRS21.NetworkInterface.IsDhcpEnabled)
                {
                    Debug.Print("dhcp enabled");
                    wifiRS21.NetworkInterface.EnableDhcp();
                    wifiRS21.NetworkInterface.EnableDynamicDns();
                }
            }

            // scan network for given ssid and join
            GHI.Networking.WiFiRS9110.NetworkParameters[] WifiScanResult = wifiRS21.NetworkInterface.Scan();
            for (int i = 0; i < WifiScanResult.Length; i++)
            {
                Debug.Print(WifiScanResult[i].Ssid + " ssid");
                if (WifiScanResult[i].Ssid == "Connectify-test")
                {
                    Debug.Print("trying to join");
                    wifiRS21.NetworkInterface.Join(WifiScanResult[i].Ssid, "abdi1990");
                    break;
                }
            }

            // wait till the device gets proper ip address
            while (wifiRS21.NetworkInterface.IPAddress == "0.0.0.0")
            {
                Debug.Print("Waiting for DHCP");
                Thread.Sleep(250);
            }
            Debug.Print("Program Started");
        }

        private void camera_BitmapStreamed (Camera sender, Bitmap e)
        {
            // take two pictures and store in byte array buff1 and buff2
            if (count == 0)
            {
                Debug.Print("first taken");
                buff1 = new byte[320 * 240 * 3 + 54];
                GHI.Utilities.Bitmaps.ConvertToFile(e, buff1);
                count++;
            }
            else if (count == 1)
            {
                // after camera streams second picture stop streaming and combine byte arrays buff1 & buff2
                camera.StopStreaming();
                buff2 = new byte[320 * 240 * 3 + 54];
                buff = new byte[buff1.Length + buff2.Length];
                GHI.Utilities.Bitmaps.ConvertToFile(e, buff2);
                Array.Copy(buff1, 0, buff, 0, buff1.Length);
                Array.Copy(buff2, 0, buff, buff1.Length, buff2.Length);
                Debug.Print("second taken");
                count = 0;
            }
        }

        private void camera_CameraConnected (Camera sender, EventArgs e)
        {
            camera.CurrentPictureResolution = Camera.PictureResolution.Resolution320x240;
        }

        private void NetworkChange_NetworkAddressChanged (object sender, EventArgs e)
        {
            Debug.Print(wifiRS21.NetworkInterface.IPAddress);
            Debug.Print("Network address changed");
            if (wifiRS21.NetworkInterface.IPAddress != "0.0.0.0")
            {
                WebServer.StartLocalServer(wifiRS21.NetworkInterface.IPAddress, 80);
                webServerIpAddress = wifiRS21.NetworkInterface.IPAddress;
                // wifi_RS21.Interface.Disconnect();
                WebServer.DefaultEvent.WebEventReceived += DefaultEvent_WebEventReceived;
                camera.StartStreaming(); // take 2 pictures  as soon as webserver is live
            }
        }

        private void NetworkChange_NetworkAvailabilityChanged (object sender, NetworkAvailabilityEventArgs e)
        {
            Debug.Print("Network availability: " + e.IsAvailable.ToString());
        }

        private void DefaultEvent_WebEventReceived (string path, WebServer.HttpMethod method, Responder responder)
        {
            string actualPath = "/";
            if (!StringHelper.IsNullOrWhiteSpace(path))
            {
                actualPath += path;
            }
            string methodName = string.Empty;
            switch (method)
            {
                case WebServer.HttpMethod.GET:
                    methodName = "GET";
                    break;
                case WebServer.HttpMethod.POST:
                    methodName = "POST";
                    break;
                case WebServer.HttpMethod.PUT:
                    methodName = "PUT";
                    break;
                case WebServer.HttpMethod.DELETE:
                    methodName = "DELETE";
                    break;
            }

            Debug.Print("HTTP " + methodName + " " + actualPath + " from " + responder.ClientEndpoint);

            if (method == WebServer.HttpMethod.GET && actualPath == "/")
            {
                Debug.Print("picture requested");
                string html = "<html><body><h1>Taken!!</h1></body></html>";
                byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(html);
                if (buff != null)
                {
                    responder.Respond(buff, "image/bmp"); // respond with combined byte array of the two images
                }
                else
                    responder.Respond(bytes, "text/html"); 
                camera.StartStreaming();  // after responding start streaming again
            }
        }
    }
}

Client code


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

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        private Timer timer1;
        int counter = 1;
        public Form1()
        {
            InitializeComponent();
        }

        private void clicked(object sender, EventArgs e)
        {

            //  MessageBox.Show("done");
            timer1 = new Timer();
            timer1.Tick += new EventHandler(timer_Tick);
            timer1.Interval = 5000;
            timer1.Start();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://192.168.137.102");

            // returned values are returned as a stream, then read into a string
            String lsResponse = string.Empty;
            using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse())
            {
                using (BinaryReader reader = new BinaryReader(lxResponse.GetResponseStream()))
                {
                    Byte[] lnByte = reader.ReadBytes((320 * 240 * 3 + 54) * 2);
                    Byte[] first = new Byte[320 * 240 * 3 + 54];
                    Byte[] second = new Byte[320 * 240 * 3 + 54];
                    Array.Copy(lnByte, 0, first, 0, first.Length);
                    Array.Copy(lnByte, first.Length, second, 0, second.Length);
                    using (FileStream lxFS = new FileStream(counter + ".bmp", FileMode.Create))
                    {
                        lxFS.Write(first, 0, first.Length);
                        counter++;
                    }
                    using (FileStream lxFSs = new FileStream(counter + ".bmp", FileMode.Create))
                    {
                        lxFSs.Write(second, 0, second.Length);
                        counter++;
                    }
                }
            }
        }
    }
}

Thanks in advance

@ welmanna@ my.bridgeport.edu -
I think:

  1. Convert that bitmap to jpg and send over wifi. Take a look on this link: https://www.ghielectronics.com/community/forum/topic?id=5742&page=1
  2. Convert that bitmap 24bit to bitmap 16bit, reduce 70K
  3. Choose another camera that you can get jpg directly.

But first of all, 320x240x3 = 150K / 5 seconds = 30K/s. I believe that SpiderI can send faster than that speed.
Second is, there is so much Debug.print in your code. Make sure all of them are disable when running without attach to VS or release.
Thrid, instead of calling GHI.Utilities.Bitmaps.ConvertToFile, Array.Copy… let PC do that.
last one, if buffers size are not change, keep them in global that you can reuse. You are creating many large buffers every time sending.

Don’t do anything with camera, just send zero buffer to see how fast wifi can be first.

Just few things that you can consider!

2 Likes

@ welmanna@ my.bridgeport.edu -
just made a little test (Spider Mainboard, not your code) with an image with a size of 165 Kbyte (stored in the Resources). In a minute I could download the image about 30 x (delay of 100 ms between the requests), means about 80 kbyte/sec.
With the Raptor Mainboard I had 50 downloads in a minute.