Programming image comparing - c#

I try to compare 2 images. For this i use 2 PreentScreens doing one after another(it is idential). When I compare this screens using pixels comparing:
public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
CompareResult cr = CompareResult.ciCompareOk;
if (bmp1.Size != bmp2.Size)
{
cr = CompareResult.ciSizeMismatch;
}
else
{
for (int x = 0; x < bmp1.Width
&& cr == CompareResult.ciCompareOk; x++)
{
for (int y = 0; y < bmp1.Height
&& cr == CompareResult.ciCompareOk; y++)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
cr = CompareResult.ciPixelMismatch;
}
}
}
return cr;
}
I get correct result that says - compare are identical, but it take a lot of time and when I'm try to hash this Bitmaps and compare it values - I get wrong result. When I compare image with itself - everything OK. What can be wrong? Here is code for hash comparing:
public enum CompareResult
{
ciCompareOk,
ciPixelMismatch,
ciSizeMismatch
};
public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
CompareResult cr = CompareResult.ciCompareOk;
//Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
cr = CompareResult.ciSizeMismatch;
}
else
{
//Convert each image to a byte array
System.Drawing.ImageConverter ic =
new System.Drawing.ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());
//Compute a hash for each image
SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);
//Compare the hash values
for (int i = 0; i < hash1.Length && i < hash2.Length
&& cr == CompareResult.ciCompareOk; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.ciPixelMismatch;
}
}
return cr;
}

Possible duplicate of How to compare Image objects with C# .NET? which contains sample code.
Another useful link is this blog post by Dominic Green. The code is somewhat smaller and uses Base64 hashing instead of SHA256 hashing. This is significantly faster, but you should be aware that comparing images is not a light operation.
But returning to the question itself, how sure are you that both images are equal? Is it possible there might be a slight difference between the two images? Your mouse cursor moved, the clock display updated, ...

Related

C# - Padding image bytes with white bytes to fill 512 x 512

I'm using Digital Persona SDK to scan fingerprints in wsq format, for requeriment I need 512 x 512 image, the SDK only export 357 x 392 image.
The sdk provide a method to compress captured image from device in wsq format and return a byte array that I can write to disk.
-I've tried to allocate a buffer of 262144 for 512 x 512 image.
-Fill the new buffer with white pixel data each byte to value 255.
-Copy the original image buffer into the new image buffer. The original image doesn’t need to be centered but it's important to make sure to copy without corrupting the image data.
To summarize I've tried to copy the old image into the upper right corner of the new image.
DPUruNet.Compression.Start();
DPUruNet.Compression.SetWsqBitrate(95, 0);
Fid capturedImage = captureResult.Data;
//Fill the new buffer with white pixel data each byte to value 255.
byte[] bytesWSQ512 = new byte[262144];
for (int i = 0; i < bytesWSQ512.Length; i++)
{
bytesWSQ512[i] = 255;
}
//Compress capturedImage and get bytes (357 x 392)
byte[] bytesWSQ = DPUruNet.Compression.CompressRaw(capturedImage.Views[0].Width, capturedImage.Views[0].Height, 500, 8, capturedImage.Views[0].RawImage, CompressionAlgorithm.COMPRESSION_WSQ_NIST);
//Copy the original image buffer into the new image buffer
for (int i = 0; i < capturedImage.Views[0].Height; i++)
{
for (int j = 0; j < capturedImage.Views[0].Width; j++)
{
bytesWSQ512[i * bytesWSQ512.Length + j ] = bytesWSQ[i * capturedImage.Views[0].Width + j];
}
}
//Write bytes to disk
File.WriteAllBytes(#"C:\Users\Admin\Desktop\bytesWSQ512.wsq", bytesWSQ512);
DPUruNet.Compression.Finish();
When running that snippet I get IndexOutOfRangeException, I don't know if the loop or the calculation of indexes for new array are right.
Here is a representation of what I'm trying to do.
If someone is trying to achieve something like this or padding a raw image, I hope this will help.
DPUruNet.Compression.
DPUruNet.Compression.SetWsqBitrate(75, 0);
Fid ISOFid = captureResult.Data;
byte[] paddedImage = PadImage8BPP(captureResult.Data.Views[0].RawImage, captureResult.Data.Views[0].Width, captureResult.Data.Views[0].Height, 512, 512, 255);
byte[] bytesWSQ512 = Compression.CompressRaw(512, 512, 500, 8, paddedImage, CompressionAlgorithm.COMPRESSION_WSQ_NIST);
And the method to resize (pad) the image is:
public byte[] PadImage8BPP(byte[] original, int original_width, int original_height, int desired_width, int desired_height, byte pad_color)
{
byte[] canvas_8bpp = new byte[desired_width * desired_height];
for (int i = 0; i < canvas_8bpp.Length; i++)
canvas_8bpp[i] = pad_color; //Fill background. Note this type of fill will fail histogram checks.
int clamp_y_begin = 0;
int clamp_y_end = original_height;
int clamp_x_begin = 0;
int clamp_x_end = original_width;
int pad_y = 0;
int pad_x = 0;
if (original_height > desired_height)
{
int crop_distance = (int)Math.Ceiling((original_height - desired_height) / 2.0);
clamp_y_begin = crop_distance;
clamp_y_end = original_height - crop_distance;
}
else
{
pad_y = (desired_height - original_height) / 2;
}
if (original_width > desired_width)
{
int crop_distance = (int)Math.Ceiling((original_width - desired_width) / 2.0);
clamp_x_begin = crop_distance;
clamp_x_end = original_width - crop_distance;
}
else
{
pad_x = (desired_width - original_width) / 2;
}
//We traverse the captured image (either whole image or subset)
for (int y = clamp_y_begin; y < clamp_y_end; y++)
{
for (int x = clamp_x_begin; x < clamp_x_end; x++)
{
byte image_pixel = original[y * original_width + x];
canvas_8bpp[(pad_y + y - clamp_y_begin) * desired_width + pad_x + x - clamp_x_begin] = image_pixel;
}
}
return canvas_8bpp;
}

C# check images are equal with tolerance

I have this code where I send images from a thermal camera. getImage() returns the actual image that is provided by the camera. There is no possibility to check directly if the camera can provide a 'new' image, so I did this method to compare two images:
class ImageCompare
{
public enum CompareResult
{
CompareOK,
SizeMismatch,
PixelMismatch
};
public static CompareResult CompareImages(Image i1, Image i2)
{
CompareResult cr = CompareResult.CompareOK;
if (i1.Size != i2.Size)
{
cr = CompareResult.SizeMismatch;
}
else
{
ImageConverter ic = new ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(i1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(i2, btImage2.GetType());
//compute hashes
SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);
for (int i = 0; i < hash1.Length && i < hash2.Length
&& cr == CompareResult.CompareOK; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.PixelMismatch;
}
}
return cr;
}
}
and here is how I use this class:
private static void HandleImageSending(Socket client, Socket s)
{
int sent;
int imageCount = 0;
long totalSize = 0;
try
{
while (true)
{
Console.WriteLine("Starting sending...");
Image old = getImage();
byte[] bmpBytes;
using (Image bmp = getImage())
using (MemoryStream ms = new MemoryStream())
{
if (ImageCompare.CompareImages(bmp, old) == ImageCompare.CompareResult.CompareOK)
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
bmpBytes = ms.ToArray();
sent = SendVarData(client, bmpBytes);
imageCount++;
totalSize += sent;
old = bmp;
}
}
}
}
catch (Exception e)
{ ... }
So my problem is that comparing by hash results in
'different' images in about 19 of 20 cases. Since the camera provides only 8 fps, there must be something wrong.
Is there a posibilty of comparing with a kind of tolerance, so maybe lets say 5 or 10 percent of the compared new image may differ to the old?
Since this is used on a mini PC, I would like to use as less CPU load as possible.
Is there anyone who can help me out here?
indexing the image (and decreasing the size) should give the same result for similar images
using
Bitmap imgtarget = imgsource.Clone(
new Rectangle(0, 0, imgsource.Width, imgsource.Height),
PixelFormat.Format8bppIndexed);
from another stackoverflow

Convert a RenderTargetBitmap to a byte[] to be displayed on a embedded screen?

I'm trying to convert a RenderTargetBitmap to a byte array that will then get sent off to an external monochrome OLED screen. I know that for the bitmap to display correctly the bit/byte alignment should be LSB to MSB & Top to Bottom:
But I can't figure out how to get the RenderTargetBitmap's pixeldata in that format.
For the moment I've got:
RenderTargetBitmap renderTargetBitmap; //This is already set higher up
DataReader reader = DataReader.FromBuffer(await renderTargetBitmap.GetPixelsAsync());
// Placeholder for reading pixels
byte[] pixel = new byte[4]; // RGBA8
// Write out pixels
int index = 0;
byte[] array = new byte[renderTargetBitmap.PixelWidth*renderTargetBitmap.PixelHeight];
using (reader)
{
//THIS IS WHERE I THINK I'M SCREWING UP
for (int x = 0; x < rHeight; x++)
{
for (int y = 0; x < rWidth; y++)
{
reader.ReadBytes(pixel);
if (pixel[2] == 255)
array[index] = 0xff;
else
array[index] = 0x00;
index++;
}
}
}
sh1106.ShowBitmap(buffer); //Send off the byte array
I faced the same issue, this is what I did to get it working (It will convert the BGRA8 output to a 1BPP output that can then be used on a monochrome display, SSD1306 in my case)
At 1BPP output means that 8 pixels are stored in 1 byte. So you need to convert every 4 bytes into 1 bit.
public async Task Draw()
{
ActiveCanvas.UpdateLayout();
ActiveCanvas.Measure(ActiveCanvas.DesiredSize);
ActiveCanvas.Arrange(new Rect(new Point(0, 0), ActiveCanvas.DesiredSize));
// Create a render bitmap and push the surface to it
RenderTargetBitmap renderBitmap = new RenderTargetBitmap();
await renderBitmap.RenderAsync(ActiveCanvas, (int)ActiveCanvas.DesiredSize.Width, (int)ActiveCanvas.DesiredSize.Height);
DataReader bitmapStream = DataReader.FromBuffer(await renderBitmap.GetPixelsAsync());
if (_device != null)
{
byte[] pixelBuffer_1BPP = new byte[(int)(renderBitmap.PixelWidth * renderBitmap.PixelHeight) / 32];
pixelBuffer_1BPP.Initialize();
using (bitmapStream)
{
while (bitmapStream.UnconsumedBufferLength > 0)
{
uint index = (uint)(renderBitmap.PixelWidth * renderBitmap.PixelHeight * 4) - bitmapStream.UnconsumedBufferLength;
for (int bit = 0; bit < 8; bit++)
{
bitmapStream.ReadBytes(BGRA8);
byte value = (byte)(((BGRA8[0] & 0x80) | (BGRA8[1] & 0x80) | (BGRA8[2] & 0x80)) == 0x80 ? 1 : 0);
pixelBuffer_1BPP[index] |= (byte)(value << (7 - bit));
}
}
_device.DrawBitmap(0, 0, pixelBuffer_1BPP, (short)renderBitmap.PixelWidth, (short)renderBitmap.PixelHeight, Colors.White);
}
}
}

How to convert a byte array (MD5 hash) into a string (36 chars)?

I've got a byte array that was created using a hash function. I would like to convert this array into a string. So far so good, it will give me hexadecimal string.
Now I would like to use something different than hexadecimal characters, I would like to encode the byte array with these 36 characters: [a-z][0-9].
How would I go about?
Edit: the reason I would to do this, is because I would like to have a smaller string, than a hexadecimal string.
I adapted my arbitrary-length base conversion function from this answer to C#:
static string BaseConvert(string number, int fromBase, int toBase)
{
var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
var length = number.Length;
var result = string.Empty;
var nibbles = number.Select(c => digits.IndexOf(c)).ToList();
int newlen;
do {
var value = 0;
newlen = 0;
for (var i = 0; i < length; ++i) {
value = value * fromBase + nibbles[i];
if (value >= toBase) {
if (newlen == nibbles.Count) {
nibbles.Add(0);
}
nibbles[newlen++] = value / toBase;
value %= toBase;
}
else if (newlen > 0) {
if (newlen == nibbles.Count) {
nibbles.Add(0);
}
nibbles[newlen++] = 0;
}
}
length = newlen;
result = digits[value] + result; //
}
while (newlen != 0);
return result;
}
As it's coming from PHP it might not be too idiomatic C#, there are also no parameter validity checks. However, you can feed it a hex-encoded string and it will work just fine with
var result = BaseConvert(hexEncoded, 16, 36);
It's not exactly what you asked for, but encoding the byte[] into hex is trivial.
See it in action.
Earlier tonight I came across a codereview question revolving around the same algorithm being discussed here. See: https://codereview.stackexchange.com/questions/14084/base-36-encoding-of-a-byte-array/
I provided a improved implementation of one of its earlier answers (both use BigInteger). See: https://codereview.stackexchange.com/a/20014/20654. The solution takes a byte[] and returns a Base36 string. Both the original and mine include simple benchmark information.
For completeness, the following is the method to decode a byte[] from an string. I'll include the encode function from the link above as well. See the text after this code block for some simple benchmark info for decoding.
const int kByteBitCount= 8; // number of bits in a byte
// constants that we use in FromBase36String and ToBase36String
const string kBase36Digits= "0123456789abcdefghijklmnopqrstuvwxyz";
static readonly double kBase36CharsLengthDivisor= Math.Log(kBase36Digits.Length, 2);
static readonly BigInteger kBigInt36= new BigInteger(36);
// assumes the input 'chars' is in big-endian ordering, MSB->LSB
static byte[] FromBase36String(string chars)
{
var bi= new BigInteger();
for (int x= 0; x < chars.Length; x++)
{
int i= kBase36Digits.IndexOf(chars[x]);
if (i < 0) return null; // invalid character
bi *= kBigInt36;
bi += i;
}
return bi.ToByteArray();
}
// characters returned are in big-endian ordering, MSB->LSB
static string ToBase36String(byte[] bytes)
{
// Estimate the result's length so we don't waste time realloc'ing
int result_length= (int)
Math.Ceiling(bytes.Length * kByteBitCount / kBase36CharsLengthDivisor);
// We use a List so we don't have to CopyTo a StringBuilder's characters
// to a char[], only to then Array.Reverse it later
var result= new System.Collections.Generic.List<char>(result_length);
var dividend= new BigInteger(bytes);
// IsZero's computation is less complex than evaluating "dividend > 0"
// which invokes BigInteger.CompareTo(BigInteger)
while (!dividend.IsZero)
{
BigInteger remainder;
dividend= BigInteger.DivRem(dividend, kBigInt36, out remainder);
int digit_index= Math.Abs((int)remainder);
result.Add(kBase36Digits[digit_index]);
}
// orientate the characters in big-endian ordering
result.Reverse();
// ToArray will also trim the excess chars used in length prediction
return new string(result.ToArray());
}
"A test 1234. Made slightly larger!" encodes to Base64 as "165kkoorqxin775ct82ist5ysteekll7kaqlcnnu6mfe7ag7e63b5"
To decode that Base36 string 1,000,000 times takes 12.6558909 seconds on my machine (I used the same build and machine conditions as provided in my answer on codereview)
You mentioned that you were dealing with a byte[] for the MD5 hash, rather than a hexadecimal string representation of it, so I think this solution provide the least overhead for you.
If you want a shorter string and can accept [a-zA-Z0-9] and + and / then look at Convert.ToBase64String
Using BigInteger (needs the System.Numerics reference)
Using BigInteger (needs the System.Numerics reference)
const string chars = "0123456789abcdefghijklmnopqrstuvwxyz";
// The result is padded with chars[0] to make the string length
// (int)Math.Ceiling(bytes.Length * 8 / Math.Log(chars.Length, 2))
// (so that for any value [0...0]-[255...255] of bytes the resulting
// string will have same length)
public static string ToBaseN(byte[] bytes, string chars, bool littleEndian = true, int len = -1)
{
if (bytes.Length == 0 || len == 0)
{
return String.Empty;
}
// BigInteger saves in the last byte the sign. > 7F negative,
// <= 7F positive.
// If we have a "negative" number, we will prepend a 0 byte.
byte[] bytes2;
if (littleEndian)
{
if (bytes[bytes.Length - 1] <= 0x7F)
{
bytes2 = bytes;
}
else
{
// Note that Array.Resize doesn't modify the original array,
// but creates a copy and sets the passed reference to the
// new array
bytes2 = bytes;
Array.Resize(ref bytes2, bytes.Length + 1);
}
}
else
{
bytes2 = new byte[bytes[0] > 0x7F ? bytes.Length + 1 : bytes.Length];
// We copy and reverse the array
for (int i = bytes.Length - 1, j = 0; i >= 0; i--, j++)
{
bytes2[j] = bytes[i];
}
}
BigInteger bi = new BigInteger(bytes2);
// A little optimization. We will do many divisions based on
// chars.Length .
BigInteger length = chars.Length;
// We pre-calc the length of the string. We know the bits of
// "information" of a byte are 8. Using Log2 we calc the bits of
// information of our new base.
if (len == -1)
{
len = (int)Math.Ceiling(bytes.Length * 8 / Math.Log(chars.Length, 2));
}
// We will build our string on a char[]
var chs = new char[len];
int chsIndex = 0;
while (bi > 0)
{
BigInteger remainder;
bi = BigInteger.DivRem(bi, length, out remainder);
chs[littleEndian ? chsIndex : len - chsIndex - 1] = chars[(int)remainder];
chsIndex++;
if (chsIndex < 0)
{
if (bi > 0)
{
throw new OverflowException();
}
}
}
// We append the zeros that we skipped at the beginning
if (littleEndian)
{
while (chsIndex < len)
{
chs[chsIndex] = chars[0];
chsIndex++;
}
}
else
{
while (chsIndex < len)
{
chs[len - chsIndex - 1] = chars[0];
chsIndex++;
}
}
return new string(chs);
}
public static byte[] FromBaseN(string str, string chars, bool littleEndian = true, int len = -1)
{
if (str.Length == 0 || len == 0)
{
return new byte[0];
}
// This should be the maximum length of the byte[] array. It's
// the opposite of the one used in ToBaseN.
// Note that it can be passed as a parameter
if (len == -1)
{
len = (int)Math.Ceiling(str.Length * Math.Log(chars.Length, 2) / 8);
}
BigInteger bi = BigInteger.Zero;
BigInteger length2 = chars.Length;
BigInteger mult = BigInteger.One;
for (int j = 0; j < str.Length; j++)
{
int ix = chars.IndexOf(littleEndian ? str[j] : str[str.Length - j - 1]);
// We didn't find the character
if (ix == -1)
{
throw new ArgumentOutOfRangeException();
}
bi += ix * mult;
mult *= length2;
}
var bytes = bi.ToByteArray();
int len2 = bytes.Length;
// BigInteger adds a 0 byte for positive numbers that have the
// last byte > 0x7F
if (len2 >= 2 && bytes[len2 - 1] == 0)
{
len2--;
}
int len3 = Math.Min(len, len2);
byte[] bytes2;
if (littleEndian)
{
if (len == bytes.Length)
{
bytes2 = bytes;
}
else
{
bytes2 = new byte[len];
Array.Copy(bytes, bytes2, len3);
}
}
else
{
bytes2 = new byte[len];
for (int i = 0; i < len3; i++)
{
bytes2[len - i - 1] = bytes[i];
}
}
for (int i = len3; i < len2; i++)
{
if (bytes[i] != 0)
{
throw new OverflowException();
}
}
return bytes2;
}
Be aware that they are REALLY slow! REALLY REALLY slow! (2 minutes for 100k). To speed them up you would probably need to rewrite the division/mod operation so that they work directly on a buffer, instead of each time recreating the scratch pads as it's done by BigInteger. And it would still be SLOW. The problem is that the time needed to encode the first byte is O(n) where n is the length of the byte array (this because all the array needs to be divided by 36). Unless you want to work with blocks of 5 bytes and lose some bits. Each symbol of Base36 carries around 5.169925001 bits. So 8 of these symbols would carry 41.35940001 bits. Very near 40 bytes.
Note that these methods can work both in little-endian mode and in big-endian mode. The endianness of the input and of the output is the same. Both methods accept a len parameter. You can use it to trim excess 0 (zeroes). Note that if you try to make an output too much small to contain the input, an OverflowException will be thrown.
System.Text.Encoding enc = System.Text.Encoding.ASCII;
string myString = enc.GetString(myByteArray);
You can play with what encoding you need:
System.Text.ASCIIEncoding,
System.Text.UnicodeEncoding,
System.Text.UTF7Encoding,
System.Text.UTF8Encoding
To match the requrements [a-z][0-9] you can use it:
Byte[] bytes = new Byte[] { 200, 180, 34 };
string result = String.Join("a", bytes.Select(x => x.ToString()).ToArray());
You will have string representation of bytes with char separator. To convert back you will need to split, and convert the string[] to byte[] using the same approach with .Select().
Usually a power of 2 is used - that way one character maps to a fixed number of bits. An alphabet of 32 bits for instance would map to 5 bits. The only challenge in that case is how to deserialize variable-length strings.
For 36 bits you could treat the data as a large number, and then:
divide by 36
add the remainder as character to your result
repeat until the division results in 0
Easier said than done perhaps.
you can use modulu.
this example encode your byte array to string of [0-9][a-z].
change it if you want.
public string byteToString(byte[] byteArr)
{
int i;
char[] charArr = new char[byteArr.Length];
for (i = 0; i < byteArr.Length; i++)
{
int byt = byteArr[i] % 36; // 36=num of availible charachters
if (byt < 10)
{
charArr[i] = (char)(byt + 48); //if % result is a digit
}
else
{
charArr[i] = (char)(byt + 87); //if % result is a letter
}
}
return new String(charArr);
}
If you don't want to lose data for de-encoding you can use this example:
public string byteToString(byte[] byteArr)
{
int i;
char[] charArr = new char[byteArr.Length*2];
for (i = 0; i < byteArr.Length; i++)
{
charArr[2 * i] = (char)((int)byteArr[i] / 36+48);
int byt = byteArr[i] % 36; // 36=num of availible charachters
if (byt < 10)
{
charArr[2*i+1] = (char)(byt + 48); //if % result is a digit
}
else
{
charArr[2*i+1] = (char)(byt + 87); //if % result is a letter
}
}
return new String(charArr);
}
and now you have a string double-lengthed when odd char is the multiply of 36 and even char is the residu. for example: 200=36*5+20 => "5k".

Problem to convert byte array to double

I have a problem to convert an byte array to double array using BitConverter.ToDouble().
Simply my program will select an image then convert the image to byte array.
Then it will convert the byte array to double array.
The problem that when I convert the byte array to the double I will get this error before the loop finish.
(Destination array is not long enough to copy all the items in the collection. Check array index and length.)
The error happen exactly at array.Length-7 position which is last seventh position before the last position on the array.
I need help to solve this problem and here is my code:
private Bitmap loadPic;
byte[] imageArray;
double[] dImageArray;
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
if (open.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(open.FileName);
loadPic = new Bitmap(pictureBox1.Image);
}
}
catch
{
throw new ApplicationException("Failed loading image");
}
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
private void btnConvert_Click(object sender, EventArgs e)
{
imageArray = imageToByteArray(loadPic);
int index = imageArray.Length;
dImageArray = new double[index];
for (int i = 0; i < index; i++)
{
dImageArray[i] = BitConverter.ToDouble(imageArray,i);
}
}
public byte[] imageToByteArray(Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, ImageFormat.Gif);
return ms.ToArray();
}
BitConverter.ToDouble(byte[], int)
uses eight bytes to construct a 64-bit double, which explains your problem (once you get to the 7th to last element, there are no longer eight bytes left). I'm guessing this is not what you want to do, based on how you set up your loop.
I imagine you want something like:
for(int i = 0; i < index; i++)
{
dImageArray[i] = (double)imageArray[i];
}
Edit - or using LINQ, just for fun:
double[] dImageArray = imageArray.Select(i => (double)i).ToArray();
On the other hand...
If BitConverter is definitely what you want, then you'll need something like:
double[] dImageArray = new double[imageArray.Length / 8];
for (int i = 0; i < dImageArray.Length; i++)
{
dImageArray[i] = BitConverter.ToDouble(imageArray, i * 8);
}
Again, based on your code, I think the first solution is what you need.
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Test();
}
private void Test()
{
Image i = Image.FromFile(#"C:\a.jpg");
Bitmap b = new Bitmap(i);
MemoryStream ms = new MemoryStream();
b.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
byte[] by = ms.ToArray();
double[] db = new double[(int)(Math.Ceiling((double)by.Length / 8))];
int startInterval = 1;
int interval = 8;
int k = 0;
byte[] bys = new byte[8];
int n = 1;
for (int m = startInterval; m <= interval && m<=by.Length; m++,n++)
{
bys[n-1] = by[m-1];
if (m == interval)
{
db[k] = BitConverter.ToDouble(bys, 0);
startInterval += 8;
interval += 8;
k++;
n = 0;
Array.Clear(bys, 0, bys.Length);
}
if (m == by.Length)
{
db[k] = BitConverter.ToDouble(bys, 0);
}
}
}
}
I think you need to back up a bit and explain what you are actually trying to do. Each BitConverter.ToDouble will convert 8 consecutive bytes into 1 double. If you start at the next position in the byte array, you are using 7 bytes that have already been used. Since each conversion will need 8 bytes, you will need to stop at Length - 7.
Anyway, you are going to end up inflating the size of the data by a factor of 8.
I think some explanation of what this is for might help you get some better answers.

Categories