I am trying to get the output of a camera and display it in a c# gui using OpenCvSharp. This is the code I have based on samples. However, this code pops up a second window, CvWindow, which I would like to remove. Is this possible? Removing the CvWindow from my code makes the camera stream not appear.
CvCapture cap= CvCapture.FromCamera(0);
CvWindow win= new CvWindow("camera");
while (CvWindow.WaitKey(10) < 0)
{
IplImage img= Capture.QueryFrame();
Bitmap bmp= BitmapConverter.ToBitmap(img);
pictureBox1.Image = bmp;
}
win.Close();
This is how I display OpenCvSharp video feeds in a Windows Form. http://www.prodigyproductionsllc.com/articles/programming/use-opencv-in-a-windows-form-application-in-c/.
The best way to hide the window is to not show it in the first place. So, remove the line where you construct a new CvWindow. Then, you need to move your while-loop into a new thread and make it continuous with something like "while(true)". If you do not run it on a separate thread, your app will freeze.
Well, it turns out using the Win32 API to hide the window was the way to go. However, you have to make sure to hide parent window of the CvWindow.
Related
I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.
I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.
I'd like to capture a screenshot of an application's window. I can do this using the below. However, is it possible to do this in parrall or does it have to happen sequentially?
I am currently making use of this:
ScreenCapture sc = new ScreenCapture(); // capture entire screen, and save it to a file
Image img = sc.CaptureScreen(); // display image in a Picture control named imageDisplay
this.imageDisplay.Image = img; // capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);
Is there any way I can take screen-shots in parallel for two or more application windows?
I have never used that library before but from your code example it seems you are not capturing a specific window but your entire screen.
it seems you want to use the function
public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
and pass it the handle of the window of the application you want to capture. It seems you can use that on as many windows as you want with the library it is just a matter of getting the handle of the correct window.
you may want to look into "threads":
http://www.albahari.com/threading/
http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx
Basically, you should launch concurrent threads to handle a specific work, eg giving the window handle as a parameter for the thread job.
I am making an application that will allow users to apply certain tools to analyse videos & images. I need help with how i actaully draw/write on the video loaded into windows media player within my form and being able to save it on. It needs to be able to lert the user draw freehand and shapes on it.
Thanks in Advance,
Chris :)
This is a non-trivial, if not impossible task to accomplish with the wmp control in winforms.
I don't know of any way to actually draw on the wmp but you could draw on a transparent panel overlaid over the wmp. This will not work will the video is playing but you can show the drawing while it is paused. I have used this technique to draw over a 3rd party video control that works similarly to wmp.(Edit - this does not seem to work with the wmp control)
However, as real transparent panels are also rather tricky in winforms, another way would be to grab an image from the video and draw on the overlaid image. Again, only when it is paused.
This commercial control does enable drawing over the video. It has an event that fires every frame that you can use to do the drawing. The big downside, though is that you can't really do anything too fancy as your drawing routine needs to finish before the next frame is drawn.
I would strongly encourage you to use WPF(even if its a wpf control hosted within a winforms app) to show your video. It is a whole lot easier to draw on video(including playing video) in wpf.
EDIT
I just tested drawing over the wmp using a transparent panel and its doesn't behave as my 3rd party control did,so I suggest you do the video playing bit in WPF and host that in your winforms app. (I just tested that too using #Callums inkcanvas suggestion and it works like a charm)
If you are using WPF, try placing an InkCanvas on top of your video and setting the Background to transparent. You can then save and load up the shapes the users draw on top of the video.
A little proof-of-concept with a picture instead of a video:
I suspect you may be using WinForms though, where this may be more difficult. If so, a good excuse to learn WPF!
EDIT: With WinForms, you would have to make your own custom control that acts as a transparent overlay and add brush strokes to it. It would be extremely hard to implement well (with transparent background, which doesn't play well with
WinForms). I would recommend using WPF if you are still at a stage you can change your application's UI. WPF works on XP and up.
EDIT2: After googling, there are some InkCanvas equivalents that people have made for WinForms, but I have no idea how good they are and may not support transparent backgrounds.
You could always have the video that you want annotated in a new WPF window and the rest of your application in WinForms.
I have found how to do this.
Here is one way in WPF using Canvas
private void buttonPlayVideo_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "All Files|*.*";
Nullable<bool> result = dlg.ShowDialog();
if (result == true) {
MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri(filename));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 960, 540);
DrawingBrush db = new DrawingBrush(vd);
canvas.Background = db;
mp.Play();
}
}
then create mouse events for Canvas and draw with it
Point startPoint, endPoint;
private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(canvas);
}
private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
endPoint = e.GetPosition(canvas);
Line myLine = new Line();
myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
myLine.X1 = startPoint.X;
myLine.Y1 = startPoint.Y;
myLine.X2 = endPoint.X;
myLine.Y2 = endPoint.Y;
myLine.HorizontalAlignment = HorizontalAlignment.Left;
myLine.VerticalAlignment = VerticalAlignment.Center;
myLine.StrokeThickness = 2;
canvas.Children.Add(myLine);
}
This can be done in WinForms but it is not easy. There is transparent form support with alpha blending in WinForms. Use the following CreateParams for the transparent overlay form: WS_EX_LAYERED, WS_EX_TRANSPARENT. Check the MSDN references for this type of window: http://msdn.microsoft.com/en-us/library/ms997507.aspx, http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#layered.
Put a transparent form above your video control and you can draw anything you want on it. Move and resize events need to be coordinated between your video window and the transparent form above it. Redrawing the overlay needs to use UpdateLayeredWindow() in user32.dll.
I learned quite a bit from this example: http://www.codeproject.com/Articles/13558/AlphaGradientPanel-an-extended-panel.
You might look at XNA (www.xna.com) from Microsoft. It is made for managed languages like c# and should support video.
I've only used it for drawing in c#, but it gets the job done.
I should also note that XNA will function as part of a regular Windows Forms app. For what it's worth, I have also prototyped something like this with Flash; Flash allows you to import each frame of the movie file into the editor and create a SWF that can respond to user interaction.
However, this approach is useless if you need to update the movie in real-time. Flash (last I checked) could only import the movie at design time.
Ok, by far and away the best way of doing this is to use Silverlight. Silverlight supports all of the major streaming formats and also provides complete access to the framebuffer.
Easy :-)
How can I show something on screen wihtout using forms?
Actually, I want to show some text and images popping on screen.
EDIT: just like i said HERE
What you can do is to create a alphatransparent form that draws the PNG and position it at the correct location and bind move etc.
http://www.codeproject.com/KB/GDI-plus/perpxalpha_sharp.aspx
PerPixelAlphaForm transparentImageForm = new PerPixelAlphaForm();
transparentImageForm.SetBitmap(<IMAGE GOES HERE>,<OPACITY GOES HERE>);
//opacity is the opacity that the image will be drawn with, a value of 255 = all transparent parts will be alpha/transparent just as much as the original PNG etc..
and you can put a timer that calls SetBitmap and changes the Opacity to fade in/out the image on the screen
And you can generate the text (on the fly) in a nice way with code from THIS article
and pass that image to the SetBitmap of the AlphaTransparent form.
EDIT: OR GO TO WPF.
I don't think you can: a form is equivalent to a window, and Windows applications draw into a window and not directly onto the screen (unless perhaps it's the backgroun/wallpaper, which I don't know about).
I think that's overdoing it but XNA will allow you to draw to the screen, but it is meant to be used for games so you will have trouble fitting it to a normal application.