C# - Copy an Image into an 8-bit Indexed Image - c#

I want to create an 8-bit indexed image from a regular 32-bit Image object.
Bitmap img = new Bitmap(imgPath); // 32-bit
Bitmap img8bit = new Bitmap(imgW, imgH, Format8bppIndexed); // 8-bit
// copy img to img8bit -- HOW?
img8bit.Save(imgNewPath, ImageFormat.Png);
I cannot use SetPixel to copy it over pixel-by-pixel since Graphics doesn't work with indexed images.
How else?

I found a C# library that converts a bitmap into a palettized (8-bit) image. The technique is fast because it calls GDI32 (the windows graphics system) directly.
To convert to an 8bpp (palettized) image with a greyscale palette, do
System.Drawing.Bitmap b0 = CopyToBpp(b,8);
If you want to convert to an image with a different palette, look at the comments in the source code of CopyToBpp for suggestions. Note that, when you convert to a 1bpp or 8bpp palettized copy, Windows will look at each pixel one by one, and will chose the palette entry that's closest to that pixel. Depending on your source image and choice of palette, you may very well end up with a resulting image that uses only half of the colours available in the palette.

Converting an arbitrary RGBA image to an 8-bit indexed bitmap is a non-trivial operation; you have to do some math to determine the top 256 colors and round the rest (or do dithering, etc).
http://support.microsoft.com/kb/319061 has the details of everything except for a good algorithm, and it should give you an idea of how to get started.

Related

Capture image from touch of PixelSense-compatible PC and save it as .bmp

I'm using Microsoft Surface 2.0 SDK with SUR40 PixelSense compatible computer. I need to capture image from it's touch and save it as .bmp. Since Surface SDK comes with RawImageVisualizer example, which displays picture from touch on the screen, I've tried to modify program for writing picture to HDD. The problem is, I get ArgumentException: Parameter is invalid during building Image from byte array captured from touch.
This is how I retrieve byte array with image data from FrameReceivedEventArgs on FrameReceived event:
event.UpdateRawImage(
ImageType.Normalized,
normalizedImage,
0, 0,
InteractiveSurface.PrimarySurfaceDevice.WorkingAreaWidth,
InteractiveSurface.PrimarySurfaceDevice.WorkingAreaHeight);
And that's how I try to write bytes as .bmp to disk:
System.Drawing.Image img;
using (System.Drawing.Image raw = System.Drawing.Image.FromStream(new MemoryStream(normalizedImage)))
{
img = raw.Clone() as System.Drawing.Bitmap;
}
img.Save("C:/img.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
So I get the exception trying to create Image from stream. Nevertheless this byte array works totally fine with Texture2D and SpriteBatch which displays it. How can I fix ArgumentException?
i've just realized, that UpdateRawImage does not return a byte representation of PNG file, but only an array of pixels. So, to build an image from it, one have to write all other parts of file structure to the array: header and color table (if needed). In many cases this can be simply done with one of System.Drawing.Bitmap constructors:
public Bitmap(
int width,
int height,
int stride,
PixelFormat format,
IntPtr scan0
)
But I was not so lucky, because UpdateRawImage returns 8bpp grayscale pixels, and PixelFormat enum doesn't support them (the most close is Format16bppGrayScale, but it uses 2 bytes for pixel, not one). So, in this particular situation, there are two obvious solutions. The first is making a new array of pixels, which meets one of PixelFormat standards (that was my choice, because I need 24-bit RGB image, despite it's actually black-white with only 256 shades). The second is writing BMP headers manually (and it's not very difficult due to open specs).

What Does the Byte[] Representation of an Image Actually Mean?

I loaded a 1 pixel image into a bitmap and then converted it to a byte[]
_Image = "test.jpg";
Bitmap testImage = new Bitmap(_Image);
ImageConverter converter = new ImageConverter();
byte[] byteTestImage = (byte[])converter.ConvertTo(testImage,typeof(byte[]));
The single pixel has RGB values (255, 116, 25). Each of these can be represented by a byte,
so I assumed that byteTestImage would correspond to this. But, byteTestImage is 635 elements in total.
What is the relationship between those bytes and the 1 pixel image?
The file you loaded is a JPG. It has certain additional information (width, height, EXIF data) not just colors. Look at https://en.wikipedia.org/wiki/JPEG
Try opening it in a hex editor. You might even be able to read info about the camera used to take it.
There is no always RGB format for single pixel in Bitmap. It all depends on format. You can have a alfa component, you can have a palette to which martix of pixels refers to and more...
Check out: Bitmap format

YcbCr image representation

I m new in image processing field. I have worked with bmp images but currently i have a problem at hand which needs image to be converted into YCbCr color space before further processing. I have read about YCbCr and conversion process but the problem is i have no idea how i will store the YCbCr data in image format and which image format will support it.
i mean in bmp images rgb components are stored in bgr format, bytes should be multiples of 4 etc, but what about YCbCr? how they are represented?
i m sorry if this sounds very lame. I googled it a little but the thing is i don't think i m going in right direction. Actually this is for my final project and i m running out of time.
Update: actually there is no need to store it in some image container although tiff and jpeg can be used. i get around it by just converting rgb to YCbCr processing it and then converting it back to rgb pixel by pixel.
Both the formats only need three bytes for each pixel. So, as long as you store your pixels in some uncompressed format such as ppm, you do not need to bother about the conversion. When you are writing, put the Y into R, Cb int G and Cr into the blue bytes respectively. When you read in the values, it is up to to your program to interpret them - the default interpretation of most image processing programs is to treat them as RGB, but you can tell it to read them in as YCbCr
If you choose to store it in some compressed format such as jpeg, the values that you read back might not be the same as the ones that you store, but the decision depends on the accuracy that you need.

C# Converting 32bpp image to 8bpp

I'm trying to convert a 32bpp screenshot image to an 8bpp (or 4bpp, or 1bpp) format using C#. I've already looked at several stackoverflow answers on similar subjects and most suggest variations using the following code:
public static Bitmap Convert(Bitmap oldbmp)
{
Bitmap newbmp = new Bitmap(oldbmp.Width, oldbmp.Height, PixelFormat.Format8bppIndexed);
Graphics gr = Graphics.FromImage(newbmp);
gr.PageUnit = GraphicsUnit.Pixel;
gr.DrawImageUnscaled(oldbmp, 0, 0);
return newbmp;
}
However, when this executes, I get a the exception: A graphics object cannot be created from an image that has an indexed pixel format. I understand that 8, 4 and 1bpp images have colour table mappings rather than the actual colour pixels themselves (as in 32 or 16bpp images) so I assume I'm missing some conversion step somewhere, but I'm fairly new to C# (coming from a C++ background) and would prefer to be able do this using native C# calls rather than resorting to PInvoking BitBlt and GetDIBits etc. Anybody able to help me solve this? Thanks.
EDIT: I should point out that I need this to be backwardly compatible to .NET framework 2.0
GDI+ in general has very poor support for indexed pixel formats. There is no simple way to convert an image with 65536 or 16 million colors into one that only has 2, 16 or 256. Colors have to be removed from the source image and that is a lossy conversion that can have very poor results. There are multiple algorithms available to accomplish this, none of them are perfect for every kind of image. This is a job for a graphics editor.
There is one trick I found. GDI+ has an image encoder for GIF files. That's a graphics format that has only 256 colors, the encoder must limit the number of colors. It uses a dithering algorithm that's suitable for photos. It does have a knack for generating a grid pattern, you'll be less than thrilled when it does. Use it like this:
public static Image Convert(Bitmap oldbmp) {
using (var ms = new MemoryStream()) {
oldbmp.Save(ms, ImageFormat.Gif);
ms.Position = 0;
return Image.FromStream(ms);
}
}
The returned image has a 8bpp pixel format with the Palette entries calculated by the encoder. You can cast it to Bitmap if necessary. By far the best thing to do is to simply not bother with indexed formats. They date from the stone age of computing back when memory was severely constrained. Or use a professional graphics editor.
AForge library is doing it perfectly using Grayscale.
var bmp8bpp = Grayscale.CommonAlgorithms.BT709.Apply(bmp);
This class is the base class for image grayscaling [...]
The filter accepts 24, 32, 48 and 64 bpp color images and produces 8
(if source is 24 or 32 bpp image) or 16 (if source is 48 or 64 bpp
image) bpp grayscale image.
Negative stride signifies the image is bottom-up (inverted). Just use the absolute of the stride if you dont care. I know that works for 24bpp images, unaware if it works for others.
You can use System.Windows.Media.Imaging in PresentationCore Assembly take a look at here for more information

Getting a LSB of a BMP binary image

i was already able to convert a BMP image into binary memory stream but im confused with detecting LSB in pixel values..
I have the byte[] stream as '10101011101010101010010' ... .. ..
First is there a way that i can filter this binary stream to pixel values and detect LSB ?
If you want to read / write the Least Significant Byte to use the bitmap to hide information you will need to load the bmp data into an image, then access the pixel-data using GetPixel(). The BMP File itself might use RLL or some other compression so you cannot access the pixel data directly.
For detecting LSB in an image, it largely depends on the algorithm used, some are harder to detect as others. Do you have the description of the LSB-variant that might be in that image?

Categories