0

I am uploading jpeg images as fast as i can to a web service (it is the requirement I have been given).

I am using async call to the web service and I calling it within a timer.

I am trying to optimise as much as possible and tend to use an old laptop for testing. On a normal/reasonable build PC all is OK. On the laptop I get high RAM usage.

I know I will get a higher RAM usage using that old laptop but I want to know the lowest spec PC the app will work on.

As you can see in the code below I am converting the jpeg image into a byte array and then I upload the byte array.

If I can reduce/compress/zip the bye array then I am hoping this will be 1 of the ways of improving memory usage.

I know jpegs are already compressed but if I compare the current byte array with the previous byre array then uploading the difference between this byte arrays I could perhaps compress it even more on the basis that some of the byte values will be zero.

If I used a video encoder (which would do the trick) I would not be real time as much I would like.

Is there an optimum way of comparing 2 byte arrays and outputting to a 3rd byte array? I have looked around but could not find an answer that I liked.

This is my code on the client:

bool _uploaded = true;
private void tmrLiveFeed_Tick(object sender, EventArgs e)
{
  try
  {
      if (_uploaded)
      {
        _uploaded = false;
          _live.StreamerAsync(Shared.Alias, imageToByteArray((Bitmap)_frame.Clone()), Guid.NewGuid().ToString()); //web service being called here
      }
  }
  catch (Exception _ex)
  {
      //do some thing but probably time out error here
  }
}

//web service has finished the client invoke 
void _live_StreamerCompleted(object sender, AsyncCompletedEventArgs e)
{
 _uploaded = true; //we are now saying we start to upload the next byte array
}

private wsLive.Live _live = new wsLive.Live(); //web service 
private byte[] imageToByteArray(Image imageIn)
{
  MemoryStream ms = new MemoryStream();
  imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg);  //convert image to best image compression
  imageIn.Dispose();
  return ms.ToArray();
}

thanks...

Andrew Simpson
  • 6,883
  • 11
  • 79
  • 179
  • You can do that through md5. – kostas ch. Nov 20 '13 at 12:07
  • Your soluttion http://stackoverflow.com/questions/3410276/need-md5-hash-for-an-in-memory-system-drawing-image – kostas ch. Nov 20 '13 at 12:10
  • hi, thanks for taking the time to reply. Isnt' that encryption rather than compression? Thanks – Andrew Simpson Nov 20 '13 at 12:15
  • You can use md5 with the way you want. If you change a byte it will create defferent md5. so you can compare jsut to md5 string which will be produced from 2 byte[]. Personally i use it all the time for these reason, to compare things. – kostas ch. Nov 20 '13 at 12:17
  • I see. I will take the time to look at it very soon and get back to you. Thank You! – Andrew Simpson Nov 20 '13 at 12:19
  • 1
    You r wellcome. I hope my comment assits you. – kostas ch. Nov 20 '13 at 12:20
  • Hi, sorry for being a bit dim here but are you suggesting i convert the before and current images to md5 hash and do a compare? How do I get the difference into a new byte array to show the changes in the images in a new image? On the server I want to convert the byte array back to a jpeg. Is this just for comparing? Thanks – Andrew Simpson Nov 20 '13 at 12:30
  • Soryy for misunderstanding, I didnot understand that you want to show the diffences. This way is just to compare "things". Of course you cannot point the diffences. – kostas ch. Nov 20 '13 at 12:35
  • Ok - np. thought I was missing something.. – Andrew Simpson Nov 20 '13 at 12:36
  • @kostasch. I gave md5 a go just to see if there was a difference between 2 images. I have found in 99% of the time that the md5s of 2 images do not match and thus tells me there are differences between the 2 images. I am assuming for motion detection that md5 would not be suitable for such a task? just curious. – Andrew Simpson Nov 22 '13 at 10:25
  • 1
    Probably is not suitable , because in motion your image will be changing continuously. For example if you have a camera out of your house and get pics, if the sun change its position the image will be different. – kostas ch. Nov 22 '13 at 10:33
  • OK - thanks for getting back to me – Andrew Simpson Nov 22 '13 at 10:33

2 Answers2

1

If your goal is to find out whether two byte arrays contain exactly the same data, you can create an MD5 hash and compare these as others have suggested. However in your question you mention you want to upload the difference which means the result of the comparison must be more than a simple yes/no.

As JPEGs are already compressed, the smallest change to the image could lead to a large difference in the binary data. I don't think any two JPEGs contain binary data similar enough to easily compare.

For BMP files you may find that changing a single pixel affects only one or a few bytes, and more importantly, the data for the pixel at a certain offset in the image is located at the same position in both binary files (given that both images are of equal size and color depth). So for BMPs the difference in binary data directly relates to the difference in the images.

In short, I don't think obtaining the binary difference between JPEG files will improve the size of the data to be sent.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
  • HI, thanks for replying. Much appreciated. I will leave the question open in the hope something has another way of looking at it but I do understand what you said. Thanks – Andrew Simpson Nov 20 '13 at 12:38
1

As C.Evenhuis said - JPEG files are compressed, and changing even few pixels results in complettly differrent file. So - comparing resulting JPEG files is useless.

BUT you can compare your Image objects - quick search results in finding this:

unsafe Bitmap PixelDiff(Bitmap a, Bitmap b)
{
    Bitmap output = new Bitmap(a.Width, a.Height, PixelFormat.Format32bppArgb);
    Rectangle rect = new Rectangle(Point.Empty, a.Size);
    using (var aData = a.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
    using (var bData = b.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
    using (var outputData = output.LockBitsDisposable(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb))
    {
        byte* aPtr = (byte*)aData.Scan0;
        byte* bPtr = (byte*)bData.Scan0;
        byte* outputPtr = (byte*)outputData.Scan0;
        int len = aData.Stride * aData.Height;
        for (int i = 0; i < len; i++)
        {
            // For alpha use the average of both images (otherwise pixels with the same alpha won't be visible)
            if ((i + 1) % 4 == 0)
                *outputPtr = (byte)((*aPtr  + *bPtr) / 2);
            else
                *outputPtr = (byte)~(*aPtr ^ *bPtr);

            outputPtr++;
            aPtr++;
            bPtr++;
        }
    }
    return output;
}
  • Hi, this looks interesting. Just got in and will take a proper look v soon. V good of u thanks. – Andrew Simpson Nov 20 '13 at 13:30
  • Hi, I took a look and used this code but it did not give me what I want. I compared 2 images and the 3rd 1 was a very white image. I will take a look at OpenCV instead. Thanks for your time though – Andrew Simpson Nov 20 '13 at 14:25