Image to array, dimension loss? - c#

I'm trying to convert a JPG image to a (double) 2d array. Using:
Image image = Image.FromFile("image.jpg");
I get a 500 x 500 image (according to image.Size.Height(Width)). But when I try to convert this to a byte array using
byte[] arr;
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
arr = ms.ToArray();
}
I get arr.GetLength(0)=35640, which is smaller than 500*500=250000. I'll convert the 1d array arr to a 2d array after that. Am I missing something?

You are not saving a pixel representation.. you are saving the bytes of a JPEG file. If you want actual pixels you need to loop over the pixels.
Also be aware that each pixel has a minimum of 3 components: Red, Green, Blue.

If you save the image in JPEG format, the pixels written to the stream will be compressed.
If you're wanting to manipulate the pixels of the image, you should probably load the image into a Bitmap and then call Bitmap.LockBits to get at the raw pixels in memory.

Related

Converting byte array to image and back again does not return the same array

I have two c# functions that convert byte[] to images and back. I thought that the two functions would be exactly reversible:
public static byte[] ImageToByte(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
return imageBytes;
}
}
public static Image ByteToImage(byte[] imageBytes)
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(imageBytes, 0, imageBytes.Length);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
}
However, if i look at the original byte array and then converted/reconverted array they are different (different lengths). I am not clear why? I would like to be able to tell if the image has been modified in my app so need to be able to compare the image array before and after.
Thanks
There is no reason to expect that both functions are reversible to get identical byte data, unless you choose an image format that does not use compression schemes controlled by variable parameters (like PNG or JPG, for example) and does not feature metadata fields that can change without altering the pixel data (like bytes 6...9 in a BMP format header, for example), or are not maintained by the infrastructure underlying System.Drawing.Image.
Instead of trying to compare the raw byte data (which can be variable depending on the image file format being used), compare the actual pixel data. In other words, load both your "before" image and "after" image into System.Drawing.Image instances, and then compare the pixel data of both images. Make sure both image instances use the same pixel format before you compare the pixel data. (Use the widest pixel format available like 64bppArgb to avoid potential reduction of the color space of the images loaded, which otherwise could spoil your efforts.) Also make sure that you don't use a "lossy" format like JPEG for your "before" and "after" pictures, otherwise the simple act of uncompressing/decoding and re-compressing/encoding of the image might change the actual pixel data.

Loading an image from a NES CHR file (i.e., a binary file) and showing on a Windows Form

I'm working on a C# form that reads graphics from a binary file and allows me to create maps with it. I'm having trouble trying to display an image on the form based on the bytes in the binary file. This binary file stores a bunch of 8x8 pixel images and each row of this image is stored in two different bytes, which I have to do some processing on. After reading all the bytes, I need to get palette data based on these bytes and then I can finally get my image colored properly.
I won't get into details of how the image processing works, since I think I can do that by myself (unless someone is curious, then I can explain in more detail - I'm basically reading a CHR file that contains patterns for a NES game and displaying a tile using the NES palette). By the end of all this processing, I have the RGB values for each pixel of the image stored as a byte array. My problem is that I don't know how to convert this byte array into a 8x8 image.
So for example, suppose I have a 8x8 tile that is just a red tile. By the end of the processing, this tile would be represented by an array like this (each pixel uses 3 bytes: byte 1 = R, byte 2 = G, byte 3 = B):
byte[] tilecolors = {255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, }
So, binary file has a bunch of these images stored in it as bytes and I want to do is transform those bytes into 8x8 images that will be displayed in an app (probably inside a picturebox, since I want the app user to use these tiles to create maps and stuff).
I tried using a function I saw on another website that reads loads an image from bytes using MemoryStream, but I get a "Parameter is not valid" error. This is the function I tried:
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
EDIT:
I got it to work by following #ckuri 's suggestion. After I calculate the RGB colors from reading the binary file, I can use the Bitmap class's SetPixel method to draw the image.

Difference between reading an image using Emgu and reading it as a byte array

I have a .png file and I did the following two things
Read the file as a byte array
byte[] arr = File.ReadAllBytes(Filename)
Read it using Emgu, read the file into Image and then converted the Bitmap to a byte array using the following.
Image<Gray,Byte> Img = new Image<Gray,Byte>(Filename);
byte[] arr = ImageToByte2(Img.Bitmap);
public static byte[] ImageToByte2(Image img)
{
using (MemoryStream stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
I have a difference in length of the byte array. I don't understand why there is a difference. Please help.
The first option reads all bytes of the file including the header, while the second one just reads the byte of the plain image.
For more info on the structure and the header of a png look here: https://en.wikipedia.org/wiki/Portable_Network_Graphics
When you use EMGU to generate the PNG byte array, you can't be sure that the compression level is the same as the PNG image you had in the first place.
There is an overload for the save method, where you can specify encoder parameters as well. If you adjust the compression level, maybe you can get the same byte length.

Get single frames byte array from multiframe dicom image using vtk gdcm

I am reading multiframe dicom as follows and get total pixel data of image in byte array.
gdcm.ImageReader _reader = new gdcm.ImageReader();
_reader.SetFileName("FileName");
_reader.Read();
byte[] byteArray= new byte[_reader.GetImage().GetBufferLength()];
_reader.GetImage().GetBuffer(byteArray);
but it gives out of memory exception for multiframes having more than 300 frames.
So I want to extract single frames pixel data in a byte array at a time.
Any idea??

Reading image to byte array and changing it

I am trying to work with MemoryStream in C#.
So, I do converting Image to byte array and byte array to Image.
Like this
var bytes = File.ReadAllBytes("1.jpg");
var ms = new MemoryStream(bytes, true);
var image = Image.FromStream(ms);
pictureBox1.Image = image;
It works fine (displaying image in picture box). But when i try to change byte array
bytes[0] = 254
It throws exception invalid parameter.
So, how I can change byte array or write bytes to stream? ms.WriteByte not works. Thanks
JPEG (JPG) file is compressed representation of an image. It has complex structure, it is not byte matrix. Modification of first byte in it will most likely render it invalid. You better apply your modifications to image. And then save image as JPEG.

Categories

Resources