How To Read File Into A Two Dimensional Array in c# - c#

I have a file (c:\kk.bmp). I want to read this file into a two dimensional array[Width,Height] of
byte and a two dimensional array[Width,Height] of Int32, such as
byte[,] byte_array = File.ReadAllBytes(filename_mpeg4); // Not correct
I want to read the file "filename_mpeg4" into two dimensions in an array of byte and array of Int32 in C#.

BMSs and MPEG4s are quite different things. A Bitmap has two dimensions. Mpeg4 or other video files store a list of two dimensional frames using complex compression algorithms. Therefore you have two space plus one time dimension. Your array would have to be three dimensional. It is not clear from your question whether you are trying to read an image (c:\kk.bmp) or a video (filename_mpeg4).
In both cases you need to decode the file. Don't try to do that yourself, it's very complicated (especially for videos).
Reading a bitmap is easy:
Bitmap myBitmap = new Bitmap(#"C:\kk.bmp");
This works for JPG, GIF, TIF and PNG as well. The decoders are integrated in the Windows OS.
You can draw on the image and do other things without converting it to some array.
// Example: Drawing a line on a bitmap
using (Graphics g = Graphics.FromImage( myBitmap )) {
g.DrawLine(Pens.Red, new Point(0, 0), new Point(100, 50));
}
If you still need to extract the pixel data into an array, this SO answer might help you: C# Getting the pixel data efficiently from System.Drawing.Bitmap
Videos are a completely different story. There is no easy answer to your question. This CodeProject might help you: http://www.codeproject.com/Articles/9676/Extracting-still-pictures-from-movie-files-with-C.

You can't do this with the current filestructure: you need to specify the length of at least one dimension. Something like:
int height = File.Read();
byte[] mp4 = File.ReadAllBytes(filename_mpeg4);
int width = mp4.length/height;
byte[,] byte_array = new byte[height,mp4.length/height];
int k = 0;
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
byte_array[i,j] = mp4[k++];
}
}

Related

Convert 12-bit Monochrome Image to 8-bit Grayscale

I have an image sensor board for embedded development for which I need to capture a stream of images and output them in 8-bit monochrome / grayscale format. The imager output is 12-bit monochrome (which takes 2 bytes per pixel).
In the code, I have an IntPtr to a memory buffer that has the 12-bit image data, from which I have to extract and convert that data down to an 8-bit image. This is represented in memory something like this (with a bright light activating the pixels):
As you can see, every second byte contains the LSB that I want to discard, thereby keeping only the odd-numbered bytes (to put it another way). The best solution I can conceptualize is to iterate through the memory, but that's the rub. I can't get that to work. What I need help with is an algorithm in C# to do this.
Here's a sample image that represents a direct creation of a Bitmap object from the IntPtr as follows:
bitmap = new Bitmap(imageWidth, imageHeight, imageWidth, PixelFormat.Format8bppIndexed, pImage);
// Failed Attempt #1
unsafe
{
IntPtr pImage; // pointer to buffer containing 12-bit image data from imager
int i = 0, imageSize = (imageWidth * imageHeight * 2); // two bytes per pixel
byte[] imageData = new byte[imageSize];
do
{
// Should I bitwise shift?
imageData[i] = (byte)(pImage + i) << 8; // Doesn't compile, need help here!
} while (i++ < imageSize);
}
// Failed Attempt #2
IntPtr pImage; // pointer to buffer containing 12-bit image data from imager
imageSize = imageWidth * imageHeight;
byte[] imageData = new byte[imageSize];
Marshal.Copy(pImage, imageData, 0, imageSize);
// I tried with and without this loop. Neither gives me images.
for (int i = 0; i < imageData.Length; i++)
{
if (0 == i % 2) imageData[i / 2] = imageData[i];
}
Bitmap bitmap;
using (var ms = new MemoryStream(imageData))
{
bitmap = new Bitmap(ms);
}
// This also introduced a memory leak somewhere.
Alternatively, if there's a way to do this with a Bitmap, byte[], MemoryStream, etc. that works, I'm all ears, but everything I've tried has failed.
Here is the algorithm that my coworkers helped formulate. It creates two new (unmanaged) pointers; one 8-bits wide and the other 16-bits.
By stepping through one word at a time and shifting off the last 4 bits of the source, we get a new 8-bit image with only the MSBs. Each buffer has the same number of words, but since the words are different sizes, they progress at different rates as we iterate over them.
unsafe
{
byte* p_bytebuffer = (byte*)pImage;
short* p_shortbuffer = (short*)pImage;
for (int i = 0; i < imageWidth * imageHeight; i++)
{
*p_bytebuffer++ = (byte)(*p_shortbuffer++ >> 4);
}
}
In terms of performance, this appears to be very fast with no perceivable difference in framerate.
Special thanks to #Herohtar for spending a substantial amount of time in chat with me attempting to help me solve this.

TIFF How to place images in an orderly manner

Friends! I have a set of small images that I need to lay out as a table in a Tiff file.
How the files should look like in the final file:
I use the LibTIFF library for this.
Tell me how this can be implemented? I implement my solution in C #, but the language does not matter, since rewriting the solution is not a problem.
var Row = 10;
var Column = 10;
var PIXEL_WIDTH = 8810;
var PIXEL_HEIGHT = 11810;
//Each small image has a resolution of 881x1181
using (Tiff tiff = Tiff.Open("big.tif", "w"))
{
tiff.SetField(TiffTag.IMAGEWIDTH, PIXEL_WIDTH);
tiff.SetField(TiffTag.IMAGELENGTH, PIXEL_HEIGHT);
tiff.SetField(TiffTag.COMPRESSION, Compression.LZW);
tiff.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);
tiff.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
tiff.SetField(TiffTag.ROWSPERSTRIP, PIXEL_HEIGHT);
tiff.SetField(TiffTag.XRESOLUTION, 120);
tiff.SetField(TiffTag.YRESOLUTION, 120);
tiff.SetField(TiffTag.BITSPERSAMPLE, 8);
tiff.SetField(TiffTag.SAMPLESPERPIXEL, 3);
tiff.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
int tileC = 0;
for (int row = 0; row < Row; row++)
{
for (int col = 0; col < Column; col++)
{
Bitmap bitmap = new Bitmap($"{row}x{col}.png");
byte[] raster = getImageRasterBytes(bitmap, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
tiff.WriteEncodedStrip(tileC++, raster, raster.Length);
}
}
tiff.WriteDirectory();
}
Thanks in advance!
First let's put aside the TIFF part of your question. The major problem is that you need to figure out how to organize the pixel data in memory before you can save the final image to any image type.
I will provide my own simple example to illustrate how that pixel data should be organized.
Let's say we want to combine 9 images in a 3x3 table.
Each image will be 3x3 pixels and 8-bit mono (1 channel).
That makes this example nice and simple with 9 bytes per image, and each image having a stride of 3 bytes per row.
The combined image will end up being 9x9 pixels, 81 bytes total.
These images are named A, B, C ... I
A0 is byte 0 of the pixel data for A, A1 is byte 1, and so on...
These images are going to be organized in a 3x3 table like this:
ABC
DEF
GHI
Then the final data layout would need to look like this:
byte[] pixelData = [
A0,A1,A2,B0,B1,B2,C0,C1,C2,
A3,A4,A5,B3,B4,B5,C3,C4,C5,
A6,A7,A8,B6,B7,B8,C6,C7,C8,
D0,D1,D2,E0,E1,E2,F0,F1,F2,
D3,D4,D5,E3,E4,E5,F3,F4,F5,
D6,D7,D8,E6,E7,E8,F6,F7,F8,
G0,G1,G2,H0,H1,H2,I0,I1,I2,
G3,G4,G5,H3,H4,H5,I3,I4,I5,
G6,G7,G8,H6,H7,H8,I6,I7,I8
];
The pixel array above could then be written to any image file you want. Including TIFF.
Notice in the array above:
As you iterate through that array from index 0 to 80, you will be jumping back and forth between the three images that are on the same row until you reach the next row entirely, where the next 3 images from that row are visited in the same pattern.
To achieve a memory layout like this, you can use several approaches.
TIFF files have support for breaking up a large image into equal-sized tiles. This could be used to achieve what you are asking for by writing each image to its own tile using the libTIFF library. There is a limitation that each TIFF tile must have dimensions that are multiples of 16.
The Graphics class in System.Drawing can be used to make one large blank image and then you can draw each sub-image into the large image at any desired position. (This is the easiest way to get what you want, but it can be slow.)
Doing it manually with a loop:
// For the example I have given above, in pseudo C# code
int composite_stride = image_stride * 3; // 3 is the number of images per row
int composite_size = composite_stride * image_height * 3 // 3 is the number of images per column
byte[] composite_pixels = new byte[composite_size];
// Loop over each image you want to combine
// We need some way to know which row/column the image is from, let that be assigned to table_row and table_col
// We are also assuming all images have the same width and height
foreach (image in table)
{
int comp_x = table_col * image.width;
int comp_y = table_row * image.height;
for (int y=0; y<image.height; y++)
{
// Calculate the array index that the current row starts at
int comp_row_start = comp_y * composite_stride;
for (int x=0; x<image.width; x++)
{
// Calculate the array index in the composite image to write to, and the source image index to copy from
int comp_index = comp_row_start + ((comp_x + x) * image.bytes_per_pixel);
int img_index = (y * image.stride) + (x * image.bytes_per_pixel);
composite_pixels[pixel_index] = image.pixels[img_index];
}
}
}

Get most similar image [duplicate]

This question already has answers here:
How can I measure the similarity between two images? [closed]
(17 answers)
Closed 5 years ago.
I have one Bitmap A and one array of Bitmap, in the array there is a Bitmap that looks the same as Bitmap A. I'm using the code below but it sometimes doesnt work, it iterates the entire array without finding it, it seems there are some minor differences, is there a way to change the function to return true if its 90% similar or pick the most similar image in the array? The array has only 6 images.
for(int i = 0; i < list.Count;i++)
{
if(ImageCompareString(image,list[i])
{
answerIndex = i;
break;
}
}
private static bool ImageCompareString(Bitmap firstImage, Bitmap secondImage)
{
MemoryStream ms = new MemoryStream();
firstImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
String firstBitmap = Convert.ToBase64String(ms.ToArray());
ms.Position = 0;
secondImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
String secondBitmap = Convert.ToBase64String(ms.ToArray());
if (firstBitmap.Equals(secondBitmap))
{
return true;
}
else
{
return false;
}
}
Of course there is such way... But you have to code it yourself.
First you shoud not compare the base64 data... You'll loose direct pixel value access and increase the size of the data to compare by more then 150% (Originaly 200% but corrected thanks to PeterDuniho's comment) in C# due to UTF16.
Second I assume that all pictures have the same fixed size. Before comparing, reduce the image size to something really small, but keep the width/height aspect. This will speed up the comparsion and also eliminates noise.
Third Iterate both pictures and compare their grayscaled pixel values. I Assume that you have resized the picture to 16x16. Since we're comparing their grayscale-values the value of one pixel is between 0 and 255. So the maximum distance between both pictures will be 16 * 16 * 256 = 65536. If both pictures are black, the distance between the pictures will be zero (100% similarity). If one picture is black and the other is white the distance will be 65535 (0% similarity).
To compare the images iterate the picture-pixels and subtract the grayscale-pixel-value-from-picture-a from the grayscale-pixel-value-of-picture-b at the point x,y and add the absolute difference value to the counter. This counter will be the total distance between both pictures.
Lets assume this counter has a value of 1000 after the comparison loop, you get the percentage-similarity by 1000 / 65535 ~ 1.5% difference (or 98.5% similarity) between both pictures.
pseudo-compare-code
long counter = 0;
long total = image.Width * image.Height * (Color.White - Color.Black);
for(int x = 0; x < image.Width; x++)
{
for(int y = 0; y < image.Height; y++)
{
var p1 = image.GetPixel(x, y);
var p2 = otherImage.GetPixel(x, y);
var g1 = ((p1.R + p1.G + p1.B) / 3);
var g2 = ((p2.R + p2.G + p2.B) / 3);
var distance = Math.Abs(g1 - g2);
counter += distance;
}
}
var similarity = 100 - ((counter / total) * 100);
This is an more or less easy approach, but you have to test this with you scenario/images. Instead of comparing grayscale-values you could also compare rgb-values. Look for distance definitions like the euclidean distance... Start and keep reading :)
EDIT
This is just a really basic approach that should explain how you can start comparing images. It does not take into account that there might be different image formats (jpeg, png, gif), color formats (indexed, 16bit, 24bit, 32bit) or images with different resolutions.

Sequential PrintScreens Comparison, Generate a difference image?

i am developing a application that save a printscreen at a regular interval, let's say 10 seconds.
In general the images are very similar, sometimes equal, so i came with the idea to create a bitmap that represents the difference between the current printscreen and the previous one.
To achieve this, i am comparing the 2 images, pixel by pixel, and when they are equal, i am setting the pixel with a Transparent Color (in the original code, i am using Bitmap.LockBits for a better performance):
for (var x = 0; x < width; y++)
for (var y = 0; y < height; y++)
{
var oldColor = lastPrint.GetPixel(x, y);
var color = currentPrint.GetPixel(x, y);
if (oldColor == color)
{
differencePrint.SetPixel(x, y, Color.Transparent);
}
}
To recover the image, i get the first printscreen and replace with the sequential bitmaps.
private void MergePrints()
{
var lastBitmap = new BitMap(firstPrint);
foreach (var print in prints.OrderBy(e => e.Date))
{
using (var difference = new Bitmap(print.Image))
{
using (var grfx = Graphics.FromImage(lastBitmap))
{
grfx.DrawImage(difference, 0, 0);
}
}
lastBitmap.Save(print.id + ".png");
}
lastBitmap.Dispose();
}
My question is: Is there a better way to generate a object that represents the difference between the 2 images, other than a new image with transparent pixels? Maybe a new class? but this class need to be persisted and of course "smaller" than a bitmap, currently i am persisting the bitmap as byte[] after comprrsing it using 7zip algorithm.
You can do so using the code in this answer
It uses LockBits and is really fast. It assumes the format to be the native ARGB pixel format.
It takes two Bitmaps as a parameter and returns the difference Bitmap.
The 3rd parameter lets you restore the original from the difference (if you store it losslessly, Png is recommended); this was written to allow faster transmission of only the difference image, because for only small differences it allows a much better compression ratio.
This sounds rather similar to your situation, right?
To answer the question directly: I can't see where you could get a better compression or a handier format than from the developers of Png.. As an added bonus you can always look at the difference for testing and immediately see the amount and the distribution of the changes..

Adding and averaging Tiff images using Emgu.CV to create an averaged Tiff image

I am taking three images and saving them as Tiff images in order to preserve the data of the image for analysis. In my program I load these three images as Emgu.CV.Image<Rgb,ushort>. I need to add these three images together and return a final tiff image that is the average of the three seperate images. What would be the best way to go about doing this?
Using the underlying method you can access the individual pixel values of images in emgucv and then find the average.
For color images EmguCV stores Red, Green and Blue Data in layer 0,1,2 of the image respectively
for (int i = 0; i < img1.Width; i++)
{
for (int j = 0; j < img1.Height; j++)
{
img4.Data[i,j,0] = (img1.Data[i,j,0] + img2.Data[i,j,0] +img3.Data[i,j,0])/3;
img4.Data[i,j,1] = (img1.Data[i,j,1] + img2.Data[i,j,1]+ img3.Data[i,j,1])/3;
img4.Data[i,j,2] = (img1.Data[i,j,2] + img2.Data[i,j,2]+ img3.Data[i,j,2])/3;
}
}
Note: The above code assumes that all the images are of equal size(height and width),if its not the case you should iterate for the image with the biggest size, and set the unavailable images's(or smaller image's) corresponding pixels to zero before adding .
You should also use some thing as Math.Floor or similar to normalize each pixel values as pixel values can't be in decimals.

Categories

Resources