I am trying to use a webcam to take photos for badges. To do this I have used the directshow.net library and examples, this has got me a webcam preview screen in .NET rendered in a picturebox as per DxSnap sample. I now wish to overlay it with a rectangle which is moveable and resizable (locked aspect ratio) so the end user drags this over the person to take an image from the webcam at the appropriate point. So it would look something like this:
To do this I thought no problem, the webcam source is put into a picture box I will just overlay it with a transparent panel or picture frame and use normal .NET code to make a rectangle on there. If I overlay a normal panel it appears above the directshow webcam output as expected. However if I use this trick to implement a transparent panel or picturebox:
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do not paint background.
}
It unfortunately appears underneath the directshow output. Is there an easy way to work around this or an alternative method. I would prefer not to delve too deeply into directshow.net if avoidable, I thought this would be an easy way to avoid it.
I have ended up using the AForge.NET project instead of DirectShow.NET. It has some really great samples and drawing over its video output is as simple as handling its video players OnPaint event since it calls it for each frame. It seems to take a bit more CPU but nothing too taxing.
The problem with overlaying is that video is displayed in a way different from regular GUI graphics, via specific method creating non-RGB surfaces (typically) on the video adapter. As a result of this, you cannot overlap video with windows, or use GDI directly.
You still can modify video on the way, or overlay video using special mixer.
See this question: Showing a semi-transparent Image object over an IVideoWindow in C# using DirectShow.NET as it discusses a similar request.
Related
If I wanted to create a form with a drawing area in a traditional Windows form, I would extend the panel class and then override the onPaint method to do my custom drawing, like so:
public class SpecialPanel : System.Windows.Forms.Panel
{
protected override void OnPaint(PaintEventArgs e)
{
Graphics G = e.Graphics;
G.DrawEllipse(new Pen(Color.Red), 50, 80, 50, 10);
}
}
But in a WPF if I attempt to extend the canvas class there is no onPaint method to override
public class SpecialCanvas : Canvas //Error no OnPaint method
{
public override OnPaint(PaintEventArgs e)
{
}
}
If I wanted to draw to a Canvas I would do so in a way similar to this:
Canvas.SetLeft(shape.shape, r.Next(1, 1150));
Canvas.SetTop(shape.shape, r.Next(1, 500));
SolidColorBrush b = new SolidColorBrush(Windows.UI.Color.FromArgb(255, (byte)r.Next(1, 255), (byte)r.Next(1, 255), (byte)r.Next(1, 255)));
shape.shape.Fill = b;
shape.shape.Stroke = b;
Cann.Children.Add(shape.shape);
Where Cann is an a canvas object and shape.shape is a Rectangle.
My question is, what are the fundamental differences between these methods of drawing to a form?
Fundamental differences between WPF and GDI/GDI+
The Windows Presentation Foundation (WPF) is fundamentally different from the Graphics Device Interface (GDI) and GDI+, requiring that many aspects of programming be approached in a different way. This topic briefly outlines the major differences.
Windows
Applications built using the GDI/GDI+ API use many windows, and reside under a parent window (MDI). Applications built in WPF have one window.
Unit of Measure
Applications built with a GDI/GDI+ API use the hardware pixel as the unit of measure. In these applications, as the resolution of the display device increases, the resulting image decreases. Applications built in WPF use the device-independent unit (1/96-inch) as the unit of measure. When the DPI of the system is 96, the two are equivalent.
Control Positioning
Applications built with GDI+ use absolute positioning. When the parent is resized the child elements do not get resized along with it. Applications built in WPF can use absolute, dynamic or data-bound positioning. With either absolute or dynamic positioning the controls are positioned relative to the parent element.
Image Basis
Images formed in GDI/GDI+ are pixel-based, raster images. Those formed in WPF can be scalable, vector images.
Rendering Engine
Both GDI and GDI+ are built on Win32. GDI is based on the concept of a device context, where applications obtain handles to the device context, and use the handles in order to interact with the device. GDI+ is a wrapper around GDI that creates a C++ Graphics object. WPF, on the other hand, is built on DirectX which means that it can take advantage of hardware acceleration when performing its drawing operations.
Rendering Mode
With GDI and GDI+, rendering uses immediate rendering: the application repaints the area that becomes invalidated. In WPF, rendering uses retained rendering: the application keeps track of the drawing information but the system performs the painting.
Painting
With GDI and GDI+, clipping is used to determine the bounds of the area that has become invalidated and needs to be painted. In WPF, painting is performed from back to front and components paint over each other.
Pens and Brushes
GDI and GDI+ use the concept of a current brush and a current pen. In WPF, the brush and pen must be passed with each drawing call.
Paint Region Optimization
Paint region optimization is an important part of painting with GDI or GDI+. In WPF it is not considered.
Events
GDI and GDI+ use events and event handler delegates using subscription/notification. WPF uses bubbling, tunneling, and direct event notification, and the event travels up and down the VisualTree.
Video and Audio
Direct support for video and audio is not provided by GDI+ or Windows Forms, but must be obtained through a media player like Windows Media Player. WPF supports video and audio directly.
source: http://www.leadtools.com/help/leadtools/v18/dh/to/leadtools.topics~leadtools.topics.differencesbetweengdiandwpf.html
In a geographical software written in C#, a PictureBox is used to show GIS map that is saved as a png file in a temporary directory. There is some geometric shapes we need to be drawn on map. We used System.Drawing methods to perform this action.
Sometimes we need to change some properties these shapes or delete them, we need to remove the shapes without making beneath them black. Drawing them again with Color.Transparent obviously doesn't work, using Graphics#Clear(Color.Transparent) doesn't work too for the same reason.
We even tried using another picture box with transparent background that is used only for purpose of drawing shapes on; so that when we use Graphics#Clear(Color.Transparent) map container remains untouched. Sounded like a perfect idea at first, but because i don't know how and why it makes map container PictureBox invisible and map viewer panel is totally black, this idea failed too.
MapViewerForm
|-- Toolbar
|-- StatusBar
|-- MapViewer Panel (Provides scrollbars)
|-- MapContainer Pictutebox
|-- Shapes drawing canvas PictureBbox (The same size and location as map container, only difference is z-order)
I prefer to use the two PictureBoxes and making 'layers' idea, i think it's less unprofessional than the other idea (I am actually a java developer and this is a C# project!), I think there should be something like java's JLayeredPane in C# to adjust z-order of those two picture boxes and omit black screen bug, But if there is a solution to draw shapes on map container itself and then clear them without losing portions of maps lying behind them i'd appreciate that answer too.
P.S: If we load map picture from file and store it in a Bitmap or Image private field and when we need to clear drawings, load image from that field with a piece of code like picMapArea.Image = MapViewer.getInstance().getMapImage(); (Note: MapViewer is a singleton class) the painted shapes will be gone but it's obviously not anything like a "good idea" because of poor performance and lagging.
Thanks in advance.
Simply draw the shapes in an event handler for the picturebox Paint event.
To restore the view, all you have to do is call the picturebox Invalidate() method, so it repaints the Image, and not draw anything in your Paint event handler.
Just use an additional Bitmap:
Bitmap original = LoadBitmap(...);
Bitmap copy = new Bitmap(original);
Graphics graph = Graphics.FromImage(copy);
// draw some extra
PictureBox1.Image = copy;
Okay, so here we go. I'm attempting to make an application, using XNA as the base because of its renderer. One of the things that is necessary in this project is to open a new window (as a dialog), in which is embedded a separate XNA render panel. I'm using this as an interactive preview panel, so I absolutely need XNA to render in there. However, it seems XNA is not very well equipped to do this. I have tried various things myself, but to no avail (either producing errors and not rendering correctly, or rendering in the wrong aspect ratio, etc.). Normally, I would post code here, but since I have had such little luck, there isn't much to post.
My application currently consists of an XNA application embedded within a Form, and I have a button to open the preview panel, which in theory should pop up as a Form Dialog, containing the XNA renderer, to allow me to draw the preview. I have been trying this for several hours, and got nowhere, so I'm asking for a bit of help here.
Thanks, anyway.
EDIT: Okay, I've made a little progress, but I have 2 problems. Firstly, any textures drawn with a sprite batch appear the right dimensions, but filled with solid black. Also, when I open the dialog, and then close it, and close the application, I get an AccessViolationException. I strongly suspect the two errors are linked in some way.
Here is my code initialising the preview dialog. (a is a custom class that essentially consists of a LinkedList of Texture2D objects).
animPrev = new AnimationPreview(a);
animPrev.Show();
My AnimationPreview class is an extension of the Form class, and contains a PreviewControl object, which is an extension of the GraphicsDeviceControl found in the XNA Winforms sample. Note that my main form extends the XNA Game class, for various reasons.
The PreviewControl object is set up like this:
protected override void Initialize()
{
sb = new SpriteBatch(GraphicsDevice);
Application.Idle += delegate { Invalidate(); };
}
And the Draw method contains:
protected override void Draw()
{
GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.Violet);
if (frame != null)
{
sb.Begin();
sb.Draw(Image, Vector2.Zero, Color.White);
sb.End();
}
}
This clears the background of the form violet, as expected, and draws a black box of the same size as Image. This is not expected. Hopefully someone can help me out here.
NOTE: An acceptable alternative would be to convert XNA Texture2D objects to System.Drawing.Image objects. However, I am using XNA 3.1, so I can't just save the texture to a stream and reload it.
Actually, after having tried this, it's a bit dodgy, and very slow, so I'd rather not do it this way.
Did you take a look at the following official tutorials / samples?
XNA WinForms Series 1: Graphics Device
XNA WinForms Series 2: Content Loading
They should explain everything in my opinion. You even find downloadable source for the samples.
I've got a PictureBox, which can be moved vertically. The image displayed in the PictureBox is a transparent GIF, so when viewed in an image viewer, it has no background.
The problem is that when I move the PictureBox in the application, the PictureBox's background moves around too strangely - almost as if the PictureBox has a background itself.
Before:
After (while moving):
Some code:
path = "C:\\note.gif";
note.Image = Image.FromFile(path);
note.Visible = true;
note.BackColor = Color.Transparent;
panel.Controls.Add(note);
I've also tried making the picturebox double buffered, but that doesn't work either.
While WinForms is poorly suited to transparency in usercontrols, it is possible. See this article here. In it the author suggests deriving from Panel rather then UserControl and overridding the OnPaintBackground method to do nothing. this will stop your background from being drawn
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//do nothing
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
// Override the CreateParams property:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
Finally, overriding the OnPaint function you can draw your picturebox.
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
//Do your drawing here
}
Using this you could create a custom picturebox with transparency, although note you will get flicker and blurring if you move it around the screen in real-time.
Using this and similar techniques we managed to get a WinForms app, Premex XPort to render with a similar branding to their website. This involved multiple transparent controls, painting hacks and all sorts to get it to display correctly.
In conclusion, the reason why Winforms does this poorly is in Win32 based technologies one control owns one pixel on the screen. There is no way to truly composite pixels with transparency as you would expect in HTML or WPF. Later Windows technologies (WPF) do this particularly well so if you really wish to make heavy use of transparency in your app I would suggest moving to this platform, at least in part (WPF can be hosted within WinForms and vice versa).
Best regards,
Win32 controls are not truly transparent.
Your choices are:
Change to WPF
Use PictureBox.Region to clip the control's unwanted ("transparent") areas
See if there are 3rd party controls which'll do what you want
I am using dshownet(first time) and C#. I have got a sample to take the web cam input and display it on a form. I now need to draw a rectangle on top of the video stream using the mouse. (the intent is to track what is inside the box from there onwards).
I heard that there is something called VMR. So I went to the dshownet samples and went through them. I didnt find any samples that use the mouse to overlay a shape on the video stream. Someone on here suggested to use colorkey. Another person said to use GDI+ and mouse handling. I tried to compile the DXLogo sample but got this error :
Error 1 Cannot create an instance of the abstract class or interface 'System.Drawing.Image' C:\Documents and Settings\TLNA\Desktop\Final Year Project\Libraries\DirectShow library 2\DirectShowSamples-2010-February\Samples\Capture\DxLogo\Capture.cs 128 32 DxLogo-2008
for the code section:
if (fileName.Length > 0)
{
m_Bitmap = new Image(fileName); // error happened here
Rectangle r = new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height);
m_bmdLogo = m_Bitmap.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
}
I know that I must go through the Bitmap9 Interface. But I really dont know where to start. Should I read the Directshow API docs.
btw I also have the book Programming Microsoft Directshow for digital video and television. I started reading that book and stopped after a few pages since the code is mainly in C++. Should I continue to read this is book ? How can I accomplish the certain mentioned tasks in C# ?
Any suggestions as how to draw on the video. Some useful links(tutorials) would be helpful.
Many Thanks
Tlna
I'm not sure why the DirectShow sample doesn't compile, but you may be able to change the problem line:
m_Bitmap = new Image(fileName);
to this:
m_Bitmap = new Bitmap(fileName);
and get it to work.
You're actually facing a pretty difficult problem here. DirectShow renders a video by drawing a series of still frames to a device context (like a PictureBox or a Form, or even the screen) many times a second (depending on whatever the frame rate is). You (as a programmer) can also (easily) render graphics directly to this same device context.
However, in order to make your drawn box appear over top of a running video, your code needs to draw the rectangle immediately after DirectShow draws each frame of the video; otherwise, the next frame will obliterate your rectangle. DirectShow objects probably have some sort of frame rendering event that you can handle, and then inside the event handler you just re-draw your box (based on the initial and current mouse coordinates, which you can get from the MouseDown and MouseMove events of whatever control you're drawing on).
Update: I just took a look at my code from when I was playing around with DirectShow.NET, and it looks like there is an event (DsEvCode.Repaint) that you could hook into and use to draw your box.
I haven't looked at the code sample you're working with, but do a search and see if you can find an OnGraphNotify() method in your code, you should be able to add something like this:
if (code == DsEvCode.Repaint)
{
// draw the box here
}
Presumably, this event is fired after each frame of the video is rendered, so if you redraw your box here every time it will appear as if the box is persisting.