Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / January 2008

Tip: Looking for answers? Try searching our database.

Image has wrong colors

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Joe Thompson - 18 Jan 2008 04:56 GMT
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
Michael C - 18 Jan 2008 05:12 GMT
>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
[quoted text clipped - 17 lines]
> 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
Joe Thompson - 18 Jan 2008 05:44 GMT
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
Peter Duniho - 18 Jan 2008 05:59 GMT
> Thank you for the reply.  I'm not sure of the format - I beleive it's 24  
> bit
[quoted text clipped - 3 lines]
> 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 - 18 Jan 2008 07:21 GMT
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
Michael C - 18 Jan 2008 07:39 GMT
> 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
Michael C - 18 Jan 2008 06:24 GMT
> Hi Michael,
>
[quoted text clipped - 5 lines]
> 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
Peter Duniho - 18 Jan 2008 06:57 GMT
> 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
Joe Thompson - 18 Jan 2008 07:12 GMT
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
Michael C - 18 Jan 2008 07:31 GMT
> Hi Michael,
>
[quoted text clipped - 9 lines]
> 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 - 18 Jan 2008 16:52 GMT
Hi Michael,

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

Thanks again,
Joe
Joe Thompson - 21 Jan 2008 19:01 GMT
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
Michael C - 21 Jan 2008 21:50 GMT
> Hi Michael,
>
[quoted text clipped - 18 lines]
> 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.

> Thanks again,
> Joe
>
> All
Joe Thompson - 18 Jan 2008 17:08 GMT
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
Michael C - 19 Jan 2008 04:51 GMT
> 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
Joe Thompson - 23 Jan 2008 00:22 GMT
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

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.