Image has wrong colors

  • Thread starter Thread starter Joe Thompson
  • Start date Start date
J

Joe Thompson

I have a Windows form program written in C# 2005.
I continually read a stream of data via TCP that comes from a video camera
(NTSC).
When I have all the data for one frame I update a picturebox (pbVideo) like
this:

pbVideo.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes), true, true);
or this
pbVideo.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));

Everything works as expected except the colors are wrong. For example, the
things that should look yellow are turquoise and the things that should be
blue appear as red or orange.

The data stream is in mjpeg format - I just pick out the frames one at a time.
Any ideas or suggestions would be appreciated...

Thank you,
Joe
 
Joe Thompson said:
I have a Windows form program written in C# 2005.
I continually read a stream of data via TCP that comes from a video camera
(NTSC).
When I have all the data for one frame I update a picturebox (pbVideo)
like
this:

pbVideo.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes), true, true);
or this
pbVideo.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));

Everything works as expected except the colors are wrong. For example,
the
things that should look yellow are turquoise and the things that should be
blue appear as red or orange.

The data stream is in mjpeg format - I just pick out the frames one at a
time.
Any ideas or suggestions would be appreciated...

What is mjpeg format? Possibly you should be using Bitmap.LockBits and
copying the data in as it is received. That way you keep only 1 copy of the
image data and can display it as it comes in.

Michael
 
Hi Michael,

Thank you for the reply. I'm not sure of the format - I beleive it's 24 bit
color. Each frame is just a jpg file. I am trying to rewrite an application
that was written on a Linux box and it displays the colors correctly (I don't
have that code).

As far as my app goes, I gather the bytes 1450 at a time until I get a full
frame. Then I build the whole bitmap at once. I'm not familiar with
LockBits - what does it do? I was hoping it was just a color map problem or
something like that.

Thank you,
Joe
 
Thank you for the reply. I'm not sure of the format - I beleive it's 24
bit
color. Each frame is just a jpg file. I am trying to rewrite an
application
that was written on a Linux box and it displays the colors correctly (I
don't
have that code).

Do you know whether the Linux code is using a plain JPEG library, or has
something custom-written for the purpose?

I would think that if the former, the code you're using should work. But
if the latter, all bets are off.

I don't know enough about the M-JPEG format to comment with specifics.
However, I do know that many video formats are _not_ RGB, and it's
possible that the same is true for the data you're receiving.

To be honest, your question doesn't sound like the sort of thing that's
likely to get a good answer in this newsgroup. You should monitor the
thread just in case, but I would look to a forum more specific to video
streaming, perhaps even specific to the device you're using (there is as
far as I know no well-defined specification for M-JPEG, so you may need
device-specific advice).

Pete
 
Joe Thompson said:
Hi Michael,

Thank you for the reply. I'm not sure of the format - I beleive it's 24
bit
color. Each frame is just a jpg file. I am trying to rewrite an
application
that was written on a Linux box and it displays the colors correctly (I
don't
have that code).

Can you save the data to a file and open it using an image program? Does it
look the same as what you get in C#?
As far as my app goes, I gather the bytes 1450 at a time until I get a
full
frame. Then I build the whole bitmap at once. I'm not familiar with
LockBits - what does it do? I was hoping it was just a color map problem
or
something like that.

LockBits gives you high speed access to the raw data in a bitmap object.
It's possible if it's coming across from a linux box that it's a little/big
endian issue and the RGB values are just back to front. If the image is
correct except that the colours are wrong then this is what you could do:
1) Create the bitmap as you are doing currently.
2) Use LockBits to 'fix' all the data in the bitmap.

Lockbits is slightly more challenging than most C# card but it's nothing too
difficult.

Try attaching the bitmap to a post, I know that's frowned apon here but we
can cope with 1450 bytes.

Michael
 
Can you save the data to a file and open it using an image program? Does
it
look the same as what you get in C#?

I suspect that if he saves the buffer out to a file, he'll get the same
results. But I agree that would be a good test. It would at least
confirm that it's the data itself that's not being interpreted correctly,
as opposed to some other problem.
LockBits gives you high speed access to the raw data in a bitmap object.
It's possible if it's coming across from a linux box that it's a
little/big
endian issue and the RGB values are just back to front.

That's not a bad guess, but I would be surprised if it's the actual
issue. Byte order for JPEG data is well-defined regardless of platform
(big-endian) so no JPEG-aware code should be messing with the order. So
unless at some point something that's not JPEG-aware is reading the byte
stream and swapping the bytes explicitly, the byte ordering within the
stream shouldn't change. And even if that did happen, more than just the
RGB values would be messed up.
Try attaching the bitmap to a post, I know that's frowned apon here but
we
can cope with 1450 bytes.

Well, a) many ISPs will block _any_ attachment, no matter how small, and
b) he's reading data 1450 at a time, but the bitmaps themselves are larger
than that. He doesn't say how large a full frame is, and it will vary
from frame to frame never mind according to the frame resolution and rate,
but I'd guess that even at a lower resolution like 320x240 a single frame
would be 20K or so.

Much better, if it's useful to share the data at all, is to put it on a
website for download. Here are links for three of the many free websites
that offer upload/download services:

http://www.filecrunch.com/
http://www.sendspace.com/
http://www.yousendit.com/

Of course, many people have some sort of personal web site or similar
where they can put files as well. In any case, copying the file to some
place like that is much better than having the data inflated some 30% or
more by the MIME encoding, and then copied everywhere in the world, to
every server carrying the newsgroup and to every user downloading
messages, even though a handful of people at most will ever actually look
at it.

:)

Pete
 
Hi Michael,

Yes, I can and do log it to a file also. When I display it in Paint or just
use "Preview" from windows it still looks messed up. The file is actually
larger than 1450 bytes, that's just how many I read at a time. The picture
is at work and I'm off until Monday.

What I meant to say is we already have a Linux laptop with an application
that receives the same data but displays is correctly. The app I'm writing
in windows doesn't. Actually, when the camera is set to black and white, the
image looks good. Just the color mode produces a bad picture. Would this be
the case if it was a big/little endian issue? Is there a way I could apply
a PixelFormat to the jpg to correct it?

Thanks for all your help,
Joe
 
Hi Peter,

I'm really not sure the format it is using - I may be able to find out
Monday. Hopefully this thread isn't buried too deep by then. I was
originally going to post this in the Graphics and Multimedia group but it
seems more of a C# issue - maybe I will though.

Thanks for the help,
Joe
 
Joe Thompson said:
Hi Michael,

Yes, I can and do log it to a file also. When I display it in Paint or
just
use "Preview" from windows it still looks messed up. The file is actually
larger than 1450 bytes, that's just how many I read at a time. The
picture
is at work and I'm off until Monday.

What I meant to say is we already have a Linux laptop with an application
that receives the same data but displays is correctly. The app I'm
writing
in windows doesn't.

That is interesting.
Actually, when the camera is set to black and white, the
image looks good. Just the color mode produces a bad picture. Would this
be
the case if it was a big/little endian issue?

Yes (although big endian might not be technically the correct term). It's
likely windows is expecting RGB when the webcam is delivering BGR.
Is there a way I could apply
a PixelFormat to the jpg to correct it?

You could fix it with a ColorMatrix which is fairly easy to do. You'd define
a matrix like this I think:

0 0 1 0 0
0 1 0 0 0
1 0 0 0 0
0 0 0 1 0
0 0 0 0 1

Try this air code:

ColorMatrix cm = new ColorMatrix( above values in an array);
Graphics g = Graphics.FromImage(myBitmap);
ImageAttributes ia = new imageAttributes();
ia.SetColorMatrix(cm);
g.DrawImage(myBitmap,,,,,ia); //<- fill in the rest of the params
g.dispose();

You can achieve the same thing using LockBits probably faster but with more
code and it needs to be unsafe code. I would probably use LockBits myself
although the above will work quite well also. I'm presuming you can draw the
bitmap onto itself, if not you might need to create a second bitmap. I've
not tested the above code but I think it should work. If you want a lockbits
example let me know. I won't be back till monday either. Have a good
weekend.

Regards,
Michael
 
Joe Thompson said:
Hi Peter,

I'm really not sure the format it is using - I may be able to find out
Monday. Hopefully this thread isn't buried too deep by then. I was
originally going to post this in the Graphics and Multimedia group but it
seems more of a C# issue - maybe I will though.

This would be your best bet I would think as these sort of issues are dealt
with all the time there:
microsoft.public.dotnet.framework.drawing

Michael
 
Hi Michael,

I'll definitely give that a try by Monday and let you know.

Thanks again,
Joe
 
Michael,

Great news - I just had a guy at work email me a bad jpg , applyied the
colormatrix and it worked! Monday I'll try it "real time" to see if I can
keep up with the fastest video rate (I think it's 20 x second). Any
suggestions on this are welcome.

Thanks again for all your help,
Joe
 
Joe Thompson said:
Michael,

Great news - I just had a guy at work email me a bad jpg , applyied the
colormatrix and it worked! Monday I'll try it "real time" to see if I can
keep up with the fastest video rate (I think it's 20 x second). Any
suggestions on this are welcome.

Yep, try this code also, I'd be suprised if it couldn't keep up with 20
frames per sec. You'll need to mark it as unsafe and allow unsafe code in
your assembly. Out of interest, if you compare the 2 methods can you post
the max framerate of each?

Bitmap bitmap = GetBitmapFromTCP(....);
int width = bitmap.Width;
int height = bitmap.Height;
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int offset = data.Stride - data.Width * 3;
byte* ptr = (byte*)data.Scan0;
for(int y = 0; y < height; y++, ptr += offset)
{
for(int x = 0; x < width; x++, ptr += 3)
{
byte swap = ptr[0];
ptr[0] = ptr[2];
ptr[2] = swap;
}
}
bitmap.LockBits(data);

Michael
 
Hi Michael,

I was able to implement and run my program using the LockBits approach. It
seems to keep up pretty well at 15 frames/sec but a little worse at 30. If I
drop the resolution from 320 x 240 to 160 x 120 it gets better.

I would still like to try it using the ColorMatrix approach. The little
test app I ran at home was much simpler - I can't seem to figure out what to
do in my real app.

I have a picturebox named pbVideo, and a byte[] named m_ImageBuff. All I
had to do was one line of code everytime I had a complete frame:

pbVideo.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));

Now I'm confused in the ColorMatrix approach - after I do g.DrawImage how do
I get that image to my picturebox? pbVideo.Image = ???

Thanks again,
Joe



All
 
Joe Thompson said:
Hi Michael,

I was able to implement and run my program using the LockBits approach.
It
seems to keep up pretty well at 15 frames/sec but a little worse at 30.
If I
drop the resolution from 320 x 240 to 160 x 120 it gets better.

I would still like to try it using the ColorMatrix approach. The little
test app I ran at home was much simpler - I can't seem to figure out what
to
do in my real app.

I have a picturebox named pbVideo, and a byte[] named m_ImageBuff. All I
had to do was one line of code everytime I had a complete frame:

pbVideo.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));

Now I'm confused in the ColorMatrix approach - after I do g.DrawImage how
do
I get that image to my picturebox? pbVideo.Image = ???

Just something like this:
Bitmap myBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));
......
g.DrawImage(myBitmap....);
pbVideo.Image = myBitmap;


But I would abandon the picturebox myself and just do this:
Graphics g = this.CreateGraphics();//this being a form
//insert code here to create color matrix
g.drawImage(myBitmap, .... )
g.Dispose();

That way you're cutting down on CPU usage a lot because you're cutting out 1
step by drawing straight to the form. I spent 4 years writing an imaging app
and only used 1 picturebox which was to display an image in the About
screen.
 
Hi Michael,

I have both methods working now:


// ColorMatrix approach - works!
//
m_bmpPicture = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));

if (m_bmpPicture.PixelFormat ==
System.Drawing.Imaging.PixelFormat.Format24bppRgb)
{
m_gfxPicture.DrawImage(m_bmpPicture, m_rctPicture, 0, 0,
m_bmpPicture.Width, m_bmpPicture.Height, GraphicsUnit.Pixel,
m_iaPicture);
}
else
{
pbVideo.Image = m_bmpPicture;
}

Or...


// LockBits approach - works!
//
m_bmpPicture = (Bitmap)Bitmap.FromStream(new MemoryStream(m_ImageBuff, 0,
m_TotalImageBytes));

if (m_bmpPicture.PixelFormat ==
System.Drawing.Imaging.PixelFormat.Format24bppRgb)
{
ConvertToRGB(ref m_bmpPicture);
}
pbVideo.Image = m_bmpPicture;

public static bool ConvertToRGB(ref Bitmap b)
{
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int offset = data.Stride - data.Width * 3;

unsafe
{
byte* ptr = (byte*)data.Scan0;
for (int y = 0; y < height; y++, ptr += offset)
{
for (int x = 0; x < width; x++, ptr += 3)
{
byte swap = ptr[0];
ptr[0] = ptr[2];
ptr[2] = swap;
}
}
}
b.UnlockBits(data);
return true;

}


Both seem to run about the same speed but I haven't actually measured them
in any way. My biggest problem now is I need to build the inital bitmap
faster. I'm collecting the video data on one port and other telemetry data
on another port.

Thanks again for all your help,
Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top