I am using a webcam to show live stream, capture images, record video etc using AForge library.
Each time I get a new frame, I assign it to a picture Box to show the live stream and i have added a tool strip for recording video when it is checked. so i did it in the same following method.
private void video_NewFrame( object sender, NewFrameEventArgs eventArgs)
{
// Assigning new frame to a picturebox
pictureBox1.Image = newFrame;
if(recordVideo.Checked)
{
writer.AddFrame(newFrame);
}
}
when the record Video tool strip is checked. I open the avi file.
writer.Open("test.avi", pictureBox1.Width, pictureBox1.Height);
and when it is unchecked i close the file.
writer.Close();
but when i start recording the video i get the following error:
Invalid Operation Exception - object is currently in use elsewhere.
Just use it like this
pictureBox1.Image = newFrame.Clone() as Bitmap;
Related
I have a program which allows the user to open an image and measure it by dragging the mouse over it. The image opens up in a picture box when you press a button. The program works after two images are opened, but not after three images are opened. After the third image, the measurements are grossly overestimated.
Here is the part of my code which opens the image:
private void openPlan_Click(object sender, EventArgs e)// open plan folder
{
pictureBox1.Image = null;
// open file dialog
OpenFileDialog open = new OpenFileDialog();
open.InitialDirectory = #"C:\Users\Admin\Documents\complete Lumber Estimation Tool\Plans\";
// image filters
if (open.ShowDialog() == DialogResult.OK)
{
trackBar1.Value = 4;
zoom = 1.0F;
imgOriginal = null;
// display image in picture box
imgOriginal = new Bitmap(open.FileName);
pictureBox1.Image = imgOriginal;
}
}
Is this mainly a problem with how a windows form program stores data?
If so, how do I make sure the program isn't using any data or parameters from the previous image?
As in my comment:
Always dispose images, specially with open file handles.
Use:
imgOriginal?.Dispose();
pictureBox1.Image?.Dispose();
instead of: .Image = null
...in a greater detail:
The Image class is using GDI, which causes to open handles. These handles are not closed automatically by just loosing the reference in your application. They are not collected by the garbrage collector (learn.microsoft.com Garbrage-Collection).
This can result in unpredictable behavior of your application or beyond.
e.g: If you load an image from a file, the open handle results in a filelock(!) also if you just wand to display the image.
For that cases, you can load the whole image into a intermediate System.IO.MemoryStream object.
Encapsulate the image from the original source like this:
var stream = new System.IO.MemoryStream(System.IO.File.ReadAllBytes(filepath));
var Image = Image.FromStream(stream);
This will load the file into the memory and the image out of it.
Take care to Dispose the stream and the Image after your use or when loading a different image.
I am making use of the AForge class library.
From this library I am using VideoSourcePlayer to take photos with the webcam.
My purpose is to create a function that allows the user to photograph images to establish them as company logo.
Not only can you choose images from the computer, but you can also capture images from the outside through the camera, since you may only want to transfer a logo of a physical support (paper) to the program.
As commented earlier in SO, (how to pause a video file played using videosourceplayer), VideoSourcePlayer does not have a Pause method or any function that allows to freeze the image.
Yes, it is true that it has the GetCurrentFrame() method, but that only gets a Bitmap from the current frame that must be passed to a PictureBox.
But I want that when the user clicks the button Capture the image of the VideoSourcePlayer simulate being frozen, and when the user presses the Delete button because he did not like the photo, then the image stops being frozen and recovers its movement.
Logic is like pausing or playing a video.
Well, there's no method for it, so I decided to look for another way to get this, and ...
If a picture is taken, use a PictureBox that contains the last frame and that is displayed on the VideoSourcePlayer, but if it is deleted, then the PictureBox is removed and the VideoSourcePlayer is returned with video.
private readonly Bitmap EmptyBitmap;
private void CaptureBtn_Click(object sender, EventArgs e)
{
Bitmap bitmap = this.VideoSource.GetCurrentVideoFrame();
ShowTakedFrame(bitmap, false);
}
private void ShowTakedFrame(Bitmap Frame, bool remove)
{
var picture = new System.Windows.Forms.PictureBox();
picture.Size = this.VideoSource.Size;
picture.Location = this.VideoSource.Location;
if (!remove)
{
this.VideoSource.Stop();
picture.Image = Frame;
this.Controls.Remove(VideoSource);
this.Controls.Add(picture);
}
else
{
this.Controls.Remove(picture);
this.Controls.Add(VideoSource);
this.VideoSource.VideoSource = this.CaptureDevice;
this.VideoSource.Start();
}
}
private void DeleteBtn_Click(object sender, EventArgs e)
{
ShowTakedFrame(EmptyBitmap, true);
}
My problem is that when capturing the photo, the image is a few seconds after the moment when you press the Capture button and when you delete the captured image, using the Delete button, the video of the VideoSourcePlayer is frozen.
Can someone help me with this?
The problem is that when you remove the PictureBox and add the VideoSourcePlayer, it creates a new object, that is, one that does not have the configuration properties of the previous one. My recommendation is that you create the capture in a different form.
I am trying to update the image by drawing circles every time mouse pointer is moved. The pixelBuffer is stored in map object and updated with CircleFilledWithGradientMethod(). I load the pixel buffer in to WriteableBitmap Bitmap and then try to display it by setting image source of an image element in my XAML UI to Bitmap. What happens, is that when I first move my mouse, I see the very first 2 circles drawn but then as I move the mouse, the image does not get updated. Why could that be? Is there a method I should call on Image to force it to redraw? The reason I use stream.WriteAsync two times, when I could have just used it one, is just to show that it is working properly.
private async void TextArea_PointerMoved(object sender, PointerRoutedEventArgs e)
{
Pixel pixel1 = new Pixel(255, 0, 0);
Pixel pixel2 = new Pixel(255, 255, 255);
map.CircleFilledWithGradient((int) pointer.Position.X, (int)pointer.Position.Y, 100, pixel1, pixel2);
using (Stream stream = Bitmap.PixelBuffer.AsStream())
{
stream.WriteAsync(map.pixelData, 0, map.pixelData.Length);
}
map.CircleFilledWithGradient((int)pointer.Position.X+100, (int)pointer.Position.Y, 100, pixel1, pixel2);
using (Stream stream = Bitmap.PixelBuffer.AsStream())
{
stream.WriteAsync(map.pixelData, 0, map.pixelData.Length);
}
this.Image.Source = Bitmap;
}
What I think is happening, is that as soon as I draw the image on the screen, it caches it, and then keeps using the old image. Or is it that the standard Image element does not support redrawing?
Update:
My Bitmap was a private class variable. If I do
WriteableBitmap Bitmap = new WriteableBitmap((int)this.ActualWidth, (int)this.Grid.RowDefinitions[1].ActualHeight);
It all starts to work, but isn't that memory inefficient? Aren't I allocating memory for each new WriteableBitmap each time I move my mouse. And as I have found out, the issue is definitely with with Image component. Why wouldn't it update when I just make changes to it's source, but updates when I change its source to a different object.
`
Is there a method I should call on Image to force it to redraw?
Close. There's a method on WriteableBitmap.
Call WriteableBitmap.Invalidate after you update it to request the refresh.
Assuming the Bitmap was already set as Image.Source, replace the line:
this.Image.Source = Bitmap;
With:
Bitmap.Invalidate();
Why wouldn't it update when I just make changes to its source, but updates when I change its source to a different object.
Setting the Image.Source to the same thing it's already set to is a noop. Most complex Properties ignore "changes" which don't change the existing value. Creating a new WriteableBitmap each time works (very inefficiently) because it's different.
I'm developing a Winform application using c# to have something like photo kiosk that we can see in shopping mall.
I managed to find ways to capture image from webcam and store the captured image using easywebcam component. However, I want to have a photo frame around the webcam streaming video hence when the image is captured, the photo frame is included as well.
I have done research for days but still can't get any idea for this. Can any guru enlighten me for this?
I've used AForge library for working with web cam from C# and I've liked how clean it's API is.
Here the samples how to add timestamp to video, take snapshot, etc:
http://www.aforgenet.com/framework/samples/video.html
If I understand correctly, you need to have original frame when taking snapshot, so you make a copy of it before painting on frame:
Image lastUneditedFrame;
private void VideoSourcePlayer_NewFrame(object sender, ref Bitmap image)
{
if (lastUneditedFrame != null)
{
lastUneditedFrame.Dispose();
}
lastUneditedFrame = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
var graphics = Graphics.FromImage(image);
// do the drawing of photo frame
graphics.Dispose();
}
// on snapshot button click, simply call lastUneditedFrame.Save();
Thanks for your reply, I tested it with the _NewFrame event that you mentioned and add in the overlay method as below:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap img = (Bitmap)eventArgs.Frame.Clone();
// Perform Overlay here
Graphics camImg = Graphics.FromImage(img);
Bitmap frame = new Bitmap(#"D:\PriusC1.png");
camImg.DrawImage(frame, new Point(100, 100));
camImg.Save();
pictureBox1.Image = img;
}
And it worked like a charm, thank you very much!
Having decided to try AForge for video and imaging stuff, I tried to implement this simple demo:
private void Main_Load(object sender, EventArgs e)
{
// enumerate video devices
FilterInfoCollection videoDevices = new FilterInfoCollection(
FilterCategory.VideoInputDevice);
// create video source
VideoCaptureDevice videoSource = new VideoCaptureDevice(
videoDevices[0].MonikerString);
// set NewFrame event handler
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
// start the video source
videoSource.Start();
}
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
this.pictureBox1.Image = eventArgs.Frame;
}
The problem is that I always get an ArgumentException, though doesn't always happen right away. It pops up on Application.Run(new Main());, but the top of the stacktrace looks like this:
at System.Drawing.Image.get_Width() at System.Drawing.Image.get_Size()
at System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
Not sure if this is relevant, but the ParamName attribute of the exception is null. I've tried wrapping the image assignment in a try...catch block, but this didn't help. I've also checked to make sure that the image is not null before assignment. I've also checked for non-null, but 0x0 sized images.
What have I done wrong? Can anyone suggest a workaround?
I think the problem is that you do not make a copy
of the passed bitmap (frame) in your event handler.
The AForge documentation says:
Since video source may have multiple clients, each client is responsible
for making a copy (cloning) of the passed video frame, because the video source
disposes its own original copy after notifying of clients.
So, if you directly assign the frame to the picture box
the bitmap could be disposed by the AForge framework while the PictureBox
is trying to draw the bitmap.