简体   繁体   中英

Convert from 8-bit indexed pixel array to Bitmap Object

I am developing a program which gets Image from a Camera device. Here is the event how I get the Image.

    private void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e)
    {
        IGrabResult res = e.GrabResult;
        byte[] pixels = res.PixelData as byte[];
        pictureBox1.Image = ByteArrayToBitmap(pixels,res.Width,res.Height, PixelFormat.Format8bppIndexed);

        //ImagePersistence.Save(ImageFileFormat.Jpeg, "tmp/tmp" + i + ".jpg", img);

    }

I can get the Pixel Data Array with the code above. And I can directly save the image with the single line of code.

ImagePersistence.Save(ImageFileFormat.Jpeg, "tmp/tmp" + i + ".jpg", img);

Now my problem starts here. I don't want to save it, I just want to create the Bitmap object from pixel data and simply show in my pictureBox1 object. I have pixel data of image but in any case I couldn't get the image correctly.

Here is ByteArrayToBitmap function;

    public Bitmap ByteArrayToBitmap(byte[] byteIn, int imwidth, int imheight, PixelFormat pixelformat)     
    {
        Bitmap picOut = new Bitmap(imwidth, imheight, pixelformat);  
        BitmapData bmpData = picOut.LockBits(new Rectangle(0, 0, imwidth, imheight), ImageLockMode.WriteOnly, pixelformat);
        IntPtr ptr = bmpData.Scan0;
        Int32 psize = bmpData.Stride * imheight;
        System.Runtime.InteropServices.Marshal.Copy(byteIn, 0, ptr, psize);
        picOut.UnlockBits(bmpData);
        return picOut;      
    }

And here is How image looks like;

抓取的图像在这里

As you can see, image is weird. First I thought if it is the camera's problem. But I have tried it with it's own program, Camera works perfectly. Something going wrong on my code.

I am giving useful informations from debug screen;

The image dimension is 3840x2748.

The size of byte array of pixel data is 10.552.320

I have made that calculation: 3840*2748 = 10.552.320 The image is not grayscale, it is RGB image,

So I Thought that pixel data includes 8-bit-indexed pixel.

I am stuck with this problem. I have tried to give you all useful information about my problem.

How can I get the image and create bitmap object correctly ?

EDIT

    public Bitmap CopyDataToBitmap(int Width, int Height, byte[] data)
    {
        var b = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);
        ColorPalette ncp = b.Palette;
        int counter = 0;
        for (int i = 32; i <= 256; i+=32) //for R channel (3 bit)
            for (int j = 32; j <= 256; j+=32)  //for G Channel (3 bit)
                for (int k = 64; k <= 256; k+=64)  //for B Channel (2 bit)
                {
                    ncp.Entries[counter] = Color.FromArgb(255,i-1,j-1,k-1);
                    counter++;
                }
        b.Palette = ncp;

        var BoundsRect = new Rectangle(0, 0, Width, Height);

        BitmapData bmpData = b.LockBits(BoundsRect,
                                        ImageLockMode.WriteOnly,
                                        PixelFormat.Format8bppIndexed);

        IntPtr ptr = bmpData.Scan0;
        int bytes = bmpData.Stride * b.Height;
        var rgbValues = new byte[bytes];
        Marshal.Copy(data, 0, ptr, bytes);

        b.UnlockBits(bmpData);
        Console.WriteLine(b.GetPixel(3648, 1145).ToString());

        return b; 
    }

I have changed algorithm with that function. I am using color palette. But result is still same.

        ColorPalette ncp = b.Palette;
        for (int i = 0; i < 257; i++)
            ncp.Entries[i] = Color.FromArgb(255, i, i, i);
        b.Palette = ncp;

When I use this palette, this time, image becomes Grayscale.

I just want to get clear RGB image.

EDIT 2

My camera's pixel format is BayerBG8. I dont know if it helps.

8-bit bitmap only uses 256 colors, it's not useful in any modern camera. The colors have to be supplied by whoever made the image. Each pixel is one byte (or 8-bits), it's a value from 0 to 256, it refers not to a color, but to an index in the color table.

for (int i = 0; i < 256; i++)//change to 256
    ncp.Entries[i] = Color.FromArgb(255, i, i, i);

This basically makes a random color table. The odds that it's the right color table is 1/(256*256*256)


BayerBG8 is raw format, it has nothing to do with 8-bit bitmap. See description

Each pixel is represented with 4 color detectors. There are only 3 colors for each pixel, so they put an extra Green detector.

The first row is blue green blue green ...
The next row is green red green red ...

BGBGBGBG...
GRGRGRGR...
BGBGBGBG...
GRGRGRGR...

You have to take a 2x2 square and get an average color, representing 1 pixel:

piexel 1: BG    piexel 2: BG ...
          GR              GR ...

Starting from 3840x2748, you end up with 1920x1374 pixels.

Each color can be represented with 3 bytes. Now you have:

BGR BGR BGR BGR BGR BGR //RGB is stored backward as BGR

That's a total of 5760 * 1374 bytes. The example below uses a simple approximation. There are two green values for each pixel, we take an average of the two green values.

int src_width = 3840;
int src_height = 2748;

int dst_width = src_width / 2;
int dst_height = src_height / 2;

byte[] destination = new byte[dst_width * dst_height * 3];
int pos = 0;
for(int row = 0; row < src_height; row += 2)
{
    for(int col = 0; col < src_width; col += 2)
    {
        int i = row * src_width + col;
        //blue from this line
        destination[pos++] = source[i];

        //green average of two greens from this line and next line:
        destination[pos++] = (source[i + 1] + source[i + src_width])/2;

        //red from the next line
        destination[pos++] = source[i + src_width + 1];
    }
}

Use destination with Format24bppRgb , size 1920x1374

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM