Save serialCameralL1 images into SD card

I have edit the code from the forum to save serialCameralL1 images into SD card. The problem is : the code can save QQVGA and QVGA images, but it can not save VGA images. the Full code is like follows:

 using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Hardware;
using System.IO;
using GTM = Gadgeteer.Modules.GHIElectronics;
using GT = Gadgeteer;
using GHI.Utilities;

namespace Gadgeteertrysave
{
    public partial class Program
    {
        private GT.Timer timer;
        Microsoft.SPOT.Bitmap image = null;

        void ProgramStarted()
        {
            this.serialCameraL1.ImageResolution = GTM.SerialCameraL1.Resolution.QQVGA;
            this.serialCameraL1.StartStreaming();


            this.timer = new GT.Timer(1);
            timer.Behavior = GT.Timer.BehaviorType.RunOnce;
            this.timer.Tick += this.timer_Tick;
            System.Threading.Thread t = new System.Threading.Thread(cameraThread);
            t.Start();
        }

        private void cameraThread()
        {
            
                serialCameraL1.StartStreaming();
                while (!serialCameraL1.NewImageReady)
                    Thread.Sleep(10);
                if (image != null)
                    image.Dispose();

                image = serialCameraL1.GetImage();
                serialCameraL1.StopStreaming();
                timer.Start();
                Thread.Sleep(2);                //Lets timer run so I can see image

                VolumeInfo[] vi2 = VolumeInfo.GetVolumes();
                if (vi2[0].IsFormatted)
                {
                    try
                    {
                        int fileSize = image.Height * image.Width * 3 + 54;
                        LargeBuffer data = new LargeBuffer(fileSize);
                        ConvertToFile(image, data.Bytes);
                        Debug.Print("finish convert");
                        string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                        string imageName = rootDirectory + @ "\Test_" + DateTime.Now.Ticks.ToString() + ".bmp";
                        FileStream FileHandle = new FileStream(imageName, FileMode.Create);
                        FileHandle.Write(data.Bytes, 0, fileSize);
                        FileHandle.Close();
                        VolumeInfo[] vi = VolumeInfo.GetVolumes();
                        for (int i = 0; i < vi.Length; i++) vi[i].FlushAll();

                    }
                    catch (Exception exp)
                    {
                        Debug.Print(exp.Message.ToString());
                    }
                }
                else
                {
                    Debug.Print("Storage is not formatted. " + "Format on PC with FAT32/FAT16 first!");
                }
                Mainboard.UnmountStorageDevice(vi2[0].Name);
                System.Threading.Thread.Sleep(30000);
            
        }
        private void timer_Tick(GT.Timer timer)
        {
            this.displayTE35.SimpleGraphics.DisplayImage(image, 0, 0);          //will not run anywhere but in a timer routine
        }

        private void ConvertToFile(Bitmap bitmap, byte[] outputBuffer)          //From old post since Bitmaps.ConvertToFile still seems broken
        {
            Debug.Print("start to convert");
            byte[] inputBuffer = bitmap.GetBitmap();
            uint width = (uint)bitmap.Width;
            uint height = (uint)bitmap.Height;

            if (outputBuffer.Length != width * height * 3 + 54) throw new System.ArgumentException("outputBuffer.Length must be width * height * 3 + 54.", "outputSize");

            System.Array.Clear(outputBuffer, 0, outputBuffer.Length);

            Utility.InsertValueIntoArray(outputBuffer, 0, 2, 19778);
            Utility.InsertValueIntoArray(outputBuffer, 2, 4, width * height * 3 + 54);
            Utility.InsertValueIntoArray(outputBuffer, 10, 4, 54);
            Utility.InsertValueIntoArray(outputBuffer, 14, 4, 40);
            Utility.InsertValueIntoArray(outputBuffer, 18, 4, width);
            Utility.InsertValueIntoArray(outputBuffer, 22, 4, (uint)(-height));
            Utility.InsertValueIntoArray(outputBuffer, 26, 2, 1);
            Utility.InsertValueIntoArray(outputBuffer, 28, 2, 24);

            for (int i = 0, j = 54; i < width * height * 4; i += 4, j += 3)
            {
                outputBuffer[j + 0] = inputBuffer[i + 2];
                outputBuffer[j + 1] = inputBuffer[i + 1];
                outputBuffer[j + 2] = inputBuffer[i + 0];
            }
        }
    }
}

When I try to save VGA images, the code will be stuck to

, and will never get a result.  It might be the buffer overflow , but I don't know how to solve this problem, does anyone can help? Many thanks.

I’d be inclined to say this is actually a memory issue not a buffer overflow. Can you have a timer that runs every second and outputs available memory as a simple measure to watch that?

@ Brett - Hi, thanks for replying.

Now I am trying to show the available memory, and would like to using the namespace System.Object, but I can not find the reference when I want to add it. I also can not find System.Management reference. Can you also give some advice about this?

From memory it’s

1 Like

@ liuyuan898@ gmail.com - which mainboard are you using? The size of a VGA image is more than 1 MByte, does your mainboard have enough ram? It should work only on G120 or G400 Mainboards.

@ RoSchmi - Hi, I am using FEZ Spider II Mainboard, when I get the VGA image from the camera, I got a “m_bitmap” value which is very big as the figure shows:

But when get an QQVGA or VGA image, “m_bitmap” has no value, it says"Cannot fetch the value of filed ‘m_bitmap’ because information about the containing class is unavailable".

I am a beginner of using GHI and couldn’t figure out what is the problem of this. Could you please help? Many thanks.

@ Sprigo - Hi , Thank you very much for this. Now I can see the available bytes available.

The VGA image bitmap seems to take up 2698223564 bytes (should it? ) which is much bigger than the available memory 6837132bytes.

Am I doing anything wrong about the bitmap?

@ liuyuan898@ gmail.com -
This problem has already been observed:
https://www.ghielectronics.com/community/forum/topic?id=18761&page=1
The reason seems to be this:
https://www.ghielectronics.com/community/forum/topic?id=10174&page=4
Reply #33
.NETMF does not allow a single allocation to exceed around 768KB

@ RoSchmi - Thanks:)

Hi Forum,

Though I have known the reason of why

doesn't work , which is because of the memory issue, I still don't know how to fix this. There is no further information about the Bitmap method "GetBitmap". I don't know how to allocate bigger memory for getting large bitmap.
And  is there anyone can help to explain the pictures I showed in [b]Reply#5[/b] ?  What does "m_bitmap"really mean?

I would be more than happy if anyone can suggest some detailed solutions, Many thank in advance!

@ liuyuan898@ gmail.com - The m_bitmap field is a pointer to native code, not a size field. GetBitmap will not work with bitmaps that require more memory than the heap allocation limit which is around 768kB.

Your code mentions that our ConvertToFile is still broken. As far as we know it works fine, if it doesn’t it’s possibly a bug we should investigate. Our ConvertToFile is implemented internally so we do not call GetBitmap.

If our ConvertToFile won’t work for you, take a look at line 149 in the SerialCameraL1 source on our Bitbucket. NETMF bitmaps use four bytes internally but the serial camera uses two bytes, so for a 640x480 image, the camera data is just below the limit (6404802 = ~614kB). You can use the raw imageData array in the camera driver and manually convert that yourself. You’ll need to extract the RGB bits yourself though since your ConvertToFile function does not expect image data in 565 format.

@ John - Hi john,

Thank you very much for your suggestions. I tried ConvertToFile function and it has the same problem with VGA images.
And I am really beginner of image processing and C#, I checked the SerialCamera_L1 source code and don’t know which function is used to extract the raw imagedata array and how to extract the RGB bit information. And why RGB565 format is not expected? Could you please give more detailed suggestions? Many many thanks!

@ Micky - You can call SerialCameraL1.GetImageData(). It will return the data that the camera sends back which is in JPEG format. You could save this data directly to the SD card if you can use JPG instead of BMP files.

@ John - Hi John,

Thank you very much for giving this alternative solutions. I just tried to save images as JPEG files, and it works. However, the JPEG file is compressed. I am very keen to know how to solve this “out of memory” exception when I want to save larger bitmap images. Is Getbitmap() function used for getting the raw bitmap array. Could you please give some more clues about how can I get the raw bitmap array without using Getbitmap( )?

Thanks.

@ Micky - Converting the file to BMP as you tried to do in the first post will not give you any higher quality since the camera itself outputs the compressed jpeg.

To get the raw byte data out of a bitmap larger than the heap limit, I can think of two things that may work: pass it to RLP and pass back chunks of it at a time or call GHI.Utilities.Bitmaps.GetBuffer(Bitmap bitmap, byte[] buffer); where buffer is 640 * 480 * 2.

@ John - Hi John,

I appreciate very much your patient explanation and helpful suggestions.