I need to save an image to disk that came from a web-cam between 5 and 10 seconds ago from when the "save" command comes in via serial port.
To get there, I have the webcam going into a pictureBox.Image (using opencv4), and then 2 Bitmap variables. Every 5 seconds a timer ticks, and Stored_bitmap_2 = Stored_bitmap_1, then Stored_bitmap_1 = (bitmap) pictureBox.Image.
When the right serial command comes in, I try to
Stored_image_2.Save("C:\Users\GreenWorld\Desktop\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
and I get a run-time error of invalid parameter.
When I do the same thing in a stand-alone project with some buttons (inside the button-click event handler), it works every time.
When I do this inside the serialPort_DataReceived handler, I get all kinds of cross-thread errors. So, I moved the save attempt to its own subroutine, and that fixed that but now this.
I am by no means a professional programmer, I'm an engineer with a simple problem and I can usually write a little simplistic code to fix my immediate issue. Please go easy on me in the explanation :-)
Sample code:
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace Weld_picture
{
public partial class Form1 : Form
{
// Create class-level accessible variables
int Welding_camera_ID = 1;
VideoCapture capture;
Mat frame;
Bitmap image;
private Thread camera;
bool isCameraRunning = false;
string Serial_command = "";
Bitmap Stored_image_1;
Bitmap Stored_image_2;
bool Image_saved = false;
string Station_ID = "GWM-PWS-01";
string File_name = "";
private void CaptureCamera() // from someone else's sample code
{
camera = new Thread(new ThreadStart(CaptureCameraCallback));
camera.Start();
}
private void CaptureCameraCallback() // from someone else's sample code
{
frame = new Mat();
capture = new VideoCapture(Welding_camera_ID);
capture.Open(Welding_camera_ID);
if (capture.IsOpened())
{
while (isCameraRunning)
{
capture.Read(frame);
image = BitmapConverter.ToBitmap(frame);
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = image;
}
}
}
public Form1()
{
InitializeComponent();
SerialPort1.Open();
}
private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string dummy;
char CR = (char)0x0D;
while (SerialPort1.BytesToRead > 0)
{
Serial_command += (char)SerialPort1.ReadByte();
}
while (Serial_command.IndexOf(CR) > 0)
{
dummy = Serial_command.Substring(0, Serial_command.IndexOf(CR));
Serial_command = Serial_command.Substring(Serial_command.IndexOf(CR) + 1, (Serial_command.Length - (Serial_command.IndexOf(CR) + 1)));
Serial_command.Trim();
dummy.Trim();
proc_Process_serial_data(dummy);
}
}
//*************************************************************************************************************************************
/* the first timer is a 5-second interval. It's the "memory" function so that if/when the save-to-disk is triggered I can store the last-time-shutter-open image */
//*************************************************************************************************************************************
private void Timer_picture_interval_Tick(object sender, EventArgs e)
{
checkBox1.Checked = !checkBox1.Checked;
Timer_picture_interval.Stop();
Stored_image_2 = Stored_image_1;
Stored_image_1 = (Bitmap) pictureBox1.Image;
Timer_picture_interval.Start();
}
//*************************************************************************************************************************************
// the second timer is a 30-second interval. It's the way to turn capture off if the PLC/camera box somehow goes off-line
//*************************************************************************************************************************************
private void Timer_camera_powerdown_Tick(object sender, EventArgs e)
{
if (isCameraRunning)
capture.Release();
isCameraRunning = false;
Timer_picture_interval.Stop();
}
//*************************************************************************************************************************************
private void proc_Process_serial_data(string Serial_string)
{
if (Serial_string.IndexOf("Still here") > 0)
{
if (!isCameraRunning)
CaptureCamera();
isCameraRunning = true;
}
if (Serial_string.IndexOf("Sun's up") > 0)
{
Timer_picture_interval.Start();
Timer_camera_powerdown.Start();
}
if (Serial_string.IndexOf("It's dark") > 0)
{
if ((Stored_image_2 != null) && (!Image_saved)) // in case there's 2 subsequent requests to save the same thing (weld stutter)
{
File_name = "C:\\Users\\GreenWorld\\Desktop\\" + Station_ID + " D" + DateTime.Now.ToString("yyyy_MM_dd THH_mm_ss") + ".jpg";
Stored_image_2.Image.Save("C:\\Users\\GreenWorld\\Desktop\\test.bmp" , System.Drawing.Imaging.ImageFormat.Bmp );
Image_saved = true;
Timer_picture_interval.Stop();
}
Timer_camera_powerdown.Start();
}
}
}
}
You likely be able to fix the cros-threading error by simply calling your proc_Process_serial_data() method within an Invoke() call.
Change:
proc_Process_serial_data(dummy);
To:
this.Invoke((MethodInvoker)delegate ()
{
proc_Process_serial_data(dummy);
});
Also, these two lines aren't actually doing anything:
Serial_command.Trim();
dummy.Trim();
To Trim() the strings, you have capture the returned strings and re-assign them to the original variables:
Serial_command = Serial_command.Trim();
dummy = dummy.Trim();
Related
I have some code below that can take the current Image and displaying it whenever I click a PushSnap Button. How can I go about having it continuously capturing and displaying the updated image in an interval (say 100 ms)
private void PushSnap_Click(object sender, EventArgs e)
{
if (mycam == null)
{
MessageBox.Show("Internal Error: mycam is null");
return; // internal error
}
string text = "";
if (IsMyFormStatus_Opened())
{
if (!mydcam.buf_alloc(3))
{
MessageBox.Show("Frame allocation failed");
return;
}
}
// start acquisition
mycam.m_capmode = CAMCAP_START.SNAP; //one time capturing where Acquisition will start after m_nFrameCount frames
if (!mycam.cap_start())
{
return;
}
MyFormStatus_Acquiring();
MyThreadCapture_Start();
}
The Following MyThreadCapture_Start()
private void MyThreadCapture_Start()
{
m_threadCapture = new Thread(new ThreadStart(OnThreadCapture));
m_threadCapture.IsBackground = true;
m_threadCapture.Start();
}
and the following OnThreadCapture()
private void OnThreadCapture()
{
using (mycamwait = new MycamWait())
{
while (True)
{
CAMWAIT eventmask = CAMWAIT.CAPEVENT.FRAMEREADY | CAMWAIT.CAPEVENT.STOPPED;
DCAMWAIT eventhappened = DCAMWAIT.NONE;
if (mycamwait.start(eventmask, ref eventhappened))
{
if (eventhappened & CAMWAIT.CAPEVENT.FRAMEREADY)
{
int NewestFrame = 0;
int FrameCount = 0;
if (mycam.cap_transferinfo(ref NewestFrame, ref FrameCount))
{
MyUpdateImage(iNewestFrame);
}
}
if (eventhappened & CAMWAIT.CAPEVENT.STOPPED)
{
bContinue = false;
if (m_cap_stopping == false && mycam.m_capmode == CAMCAP_START.SNAP)
{
//cap_stop() happens automatically, therefore update the main dialog
//MySnapCaptureFinished();
}
}
}
}
}
Afterwards the Display is updated in the following way
private void UpdateDisplay()
{
Image oldImg = PicDisplay.Image;
if (m_bitmap != null)
{
// Show center of image
Int32 y0 = (m_image.height - PicDisplay.Height) / 2;
Int32 x0 = (m_image.width - PicDisplay.Width) / 2;
Rectangle rc = new Rectangle(x0, y0, PicDisplay.Width, PicDisplay.Height);
Bitmap bmp = new Bitmap(PicDisplay.Width, PicDisplay.Height, PixelFormat.Format24bppRgb);
using (var gr = Graphics.FromImage(bmp))
{
gr.DrawImage(m_bitmap, 0, 0, rc, GraphicsUnit.Pixel);
}
PicDisplay.Image = bmp;
PicDisplay.Refresh();
}
else
{
PicDisplay.Image = null;
}
if (oldImg != null)
oldImg.Dispose();
}
I would really recommend using Tasks instead of Threads. That should let you update your methods to take parameters and return results:
Image CaptureImage(); // I.e. similar code to OnThreadCapture
UpdateDisplay(Image);
And capture an image like:
public async void PushSnap_Click(){
...
try{
var image = await Task.Run(CaptureImage);
DisplayImage(image);
}
catch{
// Handle exceptions
}
That should let you simply rewrite your capture code to use a loop if you want live capture:
while(showLiveImagesBool){
var image = await Task.Run(CaptureImage);
DisplayImage(image);
}
The await-part should ensure the UI thread is not blocked while waiting for an image to be captured. If you do not want to show every image you might use a timer instead of a loop, just pick a timer that runs on the UI thread.
Keep in mind that showing live images will require a bit more performance, so you might need to optimize display and/or capture code. Ideally you should reuse image buffers when doing the capturing and displaying, otherwise you will allocate a fair amount of large objects that require a 2 gen GC to clean up.
I need to change the image by clicking on pictureBox, but when I click it again I can't return former picture
Here is my code:
private void PictureBox_Click(object sender, EventArgs e)
{
if (pictureBox.Image == Properties.Resources.openeye)
pictureBox.Image = Properties.Resources.closeeye;
else
pictureBox.Image = Properties.Resources.openeye;
}
How can I fix it?
Here's an example that demonstrates it with two images. One of an "x" another of an "o".
As you can see, the form has two instance variables x and o to store each of the Image objects. There is another flag field called isX which the ClickHandle event handler uses to check which image is currently displayed and switch to the other image, the event handler then toggles the isX field so the next click responds properly.
public void Main(string[] args)
{
var f1 = new Form1(); // form instance that holds the PictureBox
Task.Run(() => Application.Run(f1)); //I'm running this from LINQPad, but this would also work in a console application.
}
public class Form1 : Form // Derives from the Form class
{
private bool isX; // private instance variable to indicate which image is diplayed
private Image x; // private instance variable storing the x image
private Image o; // private instance variable storing the o image
// the picture box this form uses
private PictureBox p;
public Form1()
{
// load the images from wherever they are stored.
// I do this at construction time to avoid doing disk IO when clicking
x = Image.FromFile(#"C:\image\path\x.png");
o = Image.FromFile(#"C:\image\path\o.png");
// Initialize the picture box
p = new PictureBox {
Name = "p1",
Size = new Size(100,100),
Location = new Point(100,100),
Image = o //Initialize with the o image
};
// register the click event handler
p.Click += this.ClickHandle;
// set the flag to false, since the o image is what we start with
this.isX = false;
// add PictureBox p to the form
this.Controls.Add(p);
}
// handles the click action, registered to the PictureBox.Click event
private void ClickHandle(object sender, EventArgs e)
{
// use the flag to check which image is shown, and display the other image
if(this.isX) // this might work with your image == check, I didn't test it
{
p.Image = this.o;
}
else
{
p.Image = this.x;
}
// set the flag to the opposite of whatever the flag currently is
this.isX = ! isX;
}
}
You can set value of picturebox image, but you cant get it that way.
U can use global variable out of method and go this way.
int i = 0;
private void PictureBox1_Click(object sender, EventArgs e)
{
if (i == 0)
{
pictureBox1.Image = Properties.Resources.close;
i++;
}
else
{
pictureBox1.Image = Properties.Resources.open;
i--;
}
}
You can use this.
private void pictureBox1_Click(object sender, EventArgs e)
{
if (pictureBox1.Image!=null&& getSignatureLen( pictureBox1.Image) == getSignatureLen(Properties.Resources.openeye))
{
pictureBox1.Image = Properties.Resources.closeeye;
}
else
{
pictureBox1.Image = PProperties.Resources.openeye;
}
}
public long getSignatureLen(Image img)
{
using (System.IO.MemoryStream mStream = new System.IO.MemoryStream())
{
img.Save(mStream, img.RawFormat);
return mStream.Length;
}
}
You can save the value in the un-used Tag property, of the PictureBox object.
pictureBox1.Tag = 1; //Set it to whatever
if (pictureBox1.Tag == "1") { } //Do your check
I’m using WinForms for my application. I’m building an image viewer. My application opens image documents (.tif) files. The application has the ability to go to the next page.
The issue is, that every time I try to rotate the image and click next, the image stays on the same page but the page number increments.
Why can’t I see the images when it’s on rotate?
How can I rotate the image and go to the next page?
In the link below I've provided a test tif document for testing purposes:
http://www.filedropper.com/sampletifdocument5pages
My Code:
FileStream _stream;
Image _myImg; // setting the selected tiff
string _fileName;
private int intCurrPage = 0; // defining the current page
private int intTotalPages = 0;
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
lblFile.Text = openFileDialog1.FileName;
// Before loading you should check the file type is an image
if (_myImg == null)
{
_fileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
File.Copy(#lblFile.Text, _fileName);
_stream = new FileStream(_fileName, FileMode.Open, FileAccess.Read);
pictureBox1.Image = Image.FromStream(_stream);
}
//pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
pictureBox1.Size = new Size(750, 1100);
// Reset the current page when loading a new image.
intCurrPage = 1;
intTotalPages = pictureBox1.Image.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
lblNumPages.Text = intTotalPages.ToString();
lblCurrPage.Text = "1";
}
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
if (intCurrPage <= (intTotalPages - 1))
{
if(Radio_90_Rotate.Checked)
{
pictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
if(Radio_180_Rotate.Checked)
{
pictureBox1.Image.RotateFlip(RotateFlipType.Rotate180FlipNone);
}
// Directly increment the active frame within the image already in the PictureBox
pictureBox1.Image.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, intCurrPage);
//page increment (Go to next page)
intCurrPage++;
// Refresh the PictureBox so that it will show the currently active frame
pictureBox1.Refresh();
lblCurrPage.Text = intCurrPage.ToString();
}
}
The RotateFlip function will change the source image and flatten it to only one page. This means we need to make copies each time you view a new page that has rotation applied.
In this solution, I use the source image and simply change pages when no rotation is applied. But when rotation is set, then a Image copy is made for each page and then the rotation is applied to the copy only.
Using your sample image it takes time to load each page. So I implemented a simple label message to let the user know it's working.
Also, you may consider looking into classes prebuilt for tiff files like: https://bitmiracle.github.io/libtiff.net/
private Image _Source = null;
private int _TotalPages = 0;
private int _CurrentPage = 0;
private void Frm_TiffViewer_Load(object sender, EventArgs e)
{
lbl_WaitMessage.Visible = false;
// These two options can be adjusted as needed and probably should be set in the form control properties directly:
pictureBox1.Size = new Size(750, 1100);
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
private void ShowProcessingImageLabel()
{
lbl_WaitMessage.Visible = true;
Application.DoEvents();
}
private void DisplayPage(int PageNumber, RotateFlipType Change)
{
if (pictureBox1.Image != null && pictureBox1.Image != _Source)
{
// Release memory for old rotated image
pictureBox1.Image.Dispose();
}
// set the variable to null for easy GC cleanup
pictureBox1.Image = null;
_Source.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, PageNumber - 1);
pictureBox1.Image = new Bitmap(_Source);
pictureBox1.Image.RotateFlip(Change);
pictureBox1.Refresh();
}
private void DisplayPage(int PageNumber)
{
ShowProcessingImageLabel();
this.lblCurrPage.Text = PageNumber.ToString();
// You could adjust the PictureBox size here for each frame OR adjust the image to fit the picturebox nicely.
if (Radio_90_Rotate.Checked == true)
{
DisplayPage(PageNumber, RotateFlipType.Rotate90FlipNone);
lbl_WaitMessage.Visible = false;
return;
}
else if (Radio_180_Rotate.Checked == true)
{
DisplayPage(PageNumber, RotateFlipType.Rotate180FlipNone);
lbl_WaitMessage.Visible = false;
return;
}
if (pictureBox1.Image != _Source)
{
if (pictureBox1.Image != null)
{
// Release memory for old copy and set the variable to null for easy GC cleanup
pictureBox1.Image.Dispose();
pictureBox1.Image = null;
}
pictureBox1.Image = _Source;
}
pictureBox1.Image.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, PageNumber-1);
pictureBox1.Refresh();
lbl_WaitMessage.Visible = false;
}
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// Before loading you should check the file type is an image
this._Source = Image.FromFile(openFileDialog1.FileName);
_TotalPages = _Source.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
_CurrentPage = 1;
lblCurrPage.Text = "1";
lblFile.Text = openFileDialog1.FileName;
this.lblNumPages.Text = _TotalPages.ToString();
DisplayPage(_CurrentPage);
}
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
if (_CurrentPage < _TotalPages)
{
_CurrentPage++;
}
DisplayPage(_CurrentPage);
}
private void b_Previous_Click(object sender, EventArgs e)
{
if (_CurrentPage > 1)
{
_CurrentPage--;
}
DisplayPage(_CurrentPage);
}
private void Radio_90_Rotate_CheckedChanged(object sender, EventArgs e)
{
DisplayPage(_CurrentPage);
}
private void Radio_180_Rotate_CheckedChanged(object sender, EventArgs e)
{
DisplayPage(_CurrentPage);
}
private void Radio_0_Default_CheckedChanged(object sender, EventArgs e)
{
DisplayPage(_CurrentPage);
}
I`m Created Custom Mode v3.1
public Image _Image_v3_1_CustomMode(Image b1, float angle,float dx,float dy,float sx,float sy)
{
Bitmap bitmap = new Bitmap(b1.Width, b1.Height);
using(Graphics ehack = Graphics.FromImage(bitmap))
{
ehack.RotateTransform(angle);
ehack.TranslateTransform(dx, dy);
ehack.ScaleTransform(sx, sy);
ehack.DrawImage(b1, 0, 0);
return bitmap;
}
}
I have a bit strange problem, which I find hard to debug
Sometimes I can't close my program and it freezes when I try to close it.
I made a large program for video image recognition.
I made a special button to close the camera. This button works with this by calling a function below, and it indeed, it does work.
private void exitcamera()
{
FinalVideo.SignalToStop();
FinalVideo.WaitForStop();
FinalVideo = null;
}
Notice that the original video was started like this
private void buttonStartCamera_Click(object sender, EventArgs e)
{
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
FinalVideo.DesiredFrameSize = new System.Drawing.Size(640, 480);
FinalVideo.DesiredFrameRate = 90;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.ProvideSnapshots = true; //snapshots
FinalVideo.Start();
}
Now my problem seems (and this is a guess because I can't debug this moment)
That some thread is still active wanting to update the main form with data.
However it might not be able to do so since that one is closing.
I think something like that is going on so I wrote on the main application form
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// Thread.Sleep(1000); // not sure about these delays might help syncing threads
ExitCamera();
Thread.Sleep(1000);
}
However with that last code in place the program has even more trouble to exit.
I would like to send the subthreads an exit, but I dont know their names (if they have a name), I dont know how to list them or to instruct them to stop they are in another dll not my part of the code. From some dll's I dont have the code.
So are there ways of listing sub threads and then close them one by one, if one presses the uppercorner right cross to exit the application?
Well I managed to debug the program, and finally found what caused the problem.
It is a little bit strange since as a button I could stop the camera using the exitcamera function.
However, inside a _formclosing event the same routine didn't work although it worked after I had marked out the waitforstop function.
private void exitcamera()
{
FinalVideo.SignalToStop();
// FinalVideo.WaitForStop(); << marking out that one solved it
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame); // as sugested
FinalVideo = null;
}
I am still a bit confused about it, why this wont work in case a closing event. But it seems to be solved by this.
Maybe you have memory leaks problems caused by the event. You could try to unhook the event while exiting the programm :
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame);
Maybe this will help.
This helped with another problem when I wanted to show a preview, click a "grab" button, change the resolution of the camera from low res to high res, grab an image, and then change back to low res for the preview. Here is what worked, even though I had to abandon it because stopping and starting the camera reset the auto exposure so the picture was awful on the grabbed image:
using AForge.Video;
using AForge.Video.DirectShow;
public partial class Form1 : Form
{
private int PreviewRefreshDelayMS = 40;
private FilterInfoCollection VideoCaptureDevices;
private VideoCaptureDevice CustomerWebcam;
private int CustomerWebcam_CapabilitiesIndexMin;
private int CustomerWebcam_CapabilitiesIndexMax;
private bool bCustomerWebcam_capture;
private Bitmap CustomerWebcam_bitmap;
private System.DateTime CustomerWebcam_nextframetime = DateTime.Now;
public Form1()
{
InitializeComponent();
}
// Some good info to make this more robust
// http://haryoktav.wordpress.com/2009/03/21/webcam-in-c-aforgenet/
//
private void button1_Click(object sender, EventArgs e)
{
CustomerWebcam = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
CustomerWebcam.NewFrame += new NewFrameEventHandler(CustomerWebcam_NewFrame);
int indexMin = -1;
int MinPixels = 0;
int indexMax = -1;
int MaxPixels = 0;
for (int i = 0; i < CustomerWebcam.VideoCapabilities.Length; i++)
{
int pixels = CustomerWebcam.VideoCapabilities[i].FrameSize.Height * CustomerWebcam.VideoCapabilities[i].FrameSize.Width;
if (indexMin == -1) { indexMin = i; MinPixels = pixels; }
if (indexMax == -1) { indexMax = i; MaxPixels = pixels; }
if (pixels < MinPixels) { indexMin = i; MinPixels = pixels; }
if (pixels > MaxPixels) { indexMax = i; MaxPixels = pixels; }
}
CustomerWebcam_CapabilitiesIndexMin = indexMin;
CustomerWebcam_CapabilitiesIndexMax = indexMax;
CustomerWebcam.VideoResolution = CustomerWebcam.VideoCapabilities[indexMin];
CustomerWebcam.DisplayPropertyPage(IntPtr.Zero);
CustomerWebcam.Start();
}
void CustomerWebcam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (CustomerWebcam_bitmap != null)
{
CustomerWebcam_bitmap.Dispose();
CustomerWebcam_bitmap = null;
}
if (bCustomerWebcam_capture)
{
CustomerWebcam_bitmap = (Bitmap)eventArgs.Frame.Clone();
System.Random rnd = new Random();
CustomerWebcam_bitmap.Save("img" + Convert.ToString((int)(rnd.NextDouble() * 10000000)) + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
bCustomerWebcam_capture = false;
((Bitmap)eventArgs.Frame).Dispose();
}
else
if (DateTime.Now > CustomerWebcam_nextframetime)
{
CustomerWebcam_bitmap = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = CustomerWebcam_bitmap;
CustomerWebcam_nextframetime = DateTime.Now.AddMilliseconds(PreviewRefreshDelayMS);
((Bitmap)eventArgs.Frame).Dispose();
}
}
private void Form1_Load(object sender, EventArgs e)
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
{
comboBox1.Items.Add(VideoCaptureDevice.Name);
}
comboBox1.SelectedIndex = 0;
}
private void button2_Click(object sender, EventArgs e)
{
CustomerWebcam.SignalToStop();
CustomerWebcam = null;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!(CustomerWebcam == null))
if (CustomerWebcam.IsRunning)
{
CustomerWebcam.SignalToStop();
CustomerWebcam = null;
}
}
private void button4_Click(object sender, EventArgs e)
{
bCustomerWebcam_capture = true;
}
}
One other thing to mention ... the AForge library was the most consistent way I was able to find for using a webcam to grab a still image and save as a JPEG without delving into the world of Windows 8 metro apps. I was hoping to use OpenCV.NET, or just the regular .NET API with DirectShow or WIA, but this was the most simple and it worked for me.
And here are some good samples that were hard to find but very useful: https://github.com/mdavid/aforge.net
I was dealing with this problem. Here is a simple way to stop the camera and close Win Form.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (FinalVideo != null)
{
if (FinalVideo.IsRunning)
{
FinalVideo.SignalToStop();
FinalVideo = null;
}
}
}
In my situation WaitForStop() was needed, but the code execution was deading inside the method.
I've replaced it right after the call to SignalToStop(), with:
while (m_Device.IsRunning) { }
This is the code involved on the AForge library:
public bool IsRunning
{
get
{
if (this.thread != null)
{
if (!this.thread.Join(0))
{
return true;
}
this.Free();
}
return false;
}
}
public void WaitForStop()
{
if (this.thread != null)
{
this.thread.Join();
this.Free();
}
}
Edit: this didn't fix the hang the 100% of times. Sometimes a call to a com object (mediaControl.Stop();) on the WorkerThread() method just took forever.
Avoid direct interaction with the form - hope to have a better solution than timer but solves problem. I
Static helper class
public static Bitmap StaticBitmap = new Bitmap(100,100);
Form
public void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
lock (StaticHelper.StaticBitmap)
{
using (Bitmap b = (Bitmap)eventArgs.Frame)
{
StaticHelper.StaticBitmap = (Bitmap)b.Clone();
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (StaticHelper.StaticBitmap)
{
pictureBox1.Image = (Bitmap)StaticHelper.StaticBitmap.Clone();
}
}
This will destroy your problem ( I have had this problem, i tried)
using System.Threading;
bool photo_was_taken = false;
private void buttonStartCamera_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(exitcamera));
thread.Start();
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
FinalVideo.DesiredFrameSize = new System.Drawing.Size(640, 480);
FinalVideo.DesiredFrameRate = 90;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.ProvideSnapshots = true; //snapshots
FinalVideo.Start();
}
private void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
// what you want to do ( your code is here )
photo_was_taken = true;
}
private void exitcamera()
{
while (!photo_was_taken)
{
Thread.Sleep(5); // you can change wait milliseconds
}
FinalVideo.SignalToStop();
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame);
//FinalVideo.WaitForStop();
while (FinalVideo.IsRunning)
{
FinalVideo.Stop();
// FinalVideo = null; >> // that is not condition
}
}
This is what you need, 100% working solutions:
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
Invoke((MethodInvoker) delegate
{
_videoSource.SignalToStop();
_videoSource.WaitForStop();
});
}
Please, let me add my working solution on closing a webcam with the wonderful library AForge.NET. It´s a pitty it development has been abandoned.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (videoCaptureSource != null)
{
while (videoCaptureSource.IsRunning) // Perhaps you need to limit the number of iterations
{
videoCaptureSource.SignalToStop();
videoCaptureSource.WaitForStop();
if (videoSourcePlayer != null)
{
videoSourcePlayer.SignalToStop();
videoSourcePlayer.WaitForStop();
//videoSourcePlayer.NewFrame -= new NewFrameEventHandler(videoSourcePlayer_NewFrame); // Uncomment this line if you have added an event handler
}
Thread.Sleep(3000);
}
videoCaptureSource = null;
videoDevices = null;
videoSourcePlayer = null;
}
}
When I only needed the frame attaching an event handler to the VideoCaptureDevice (not the VideoSourcePlayer) I couldn´t stop the video from the VideoCaptureDevice, instead I used an invisible VideoSourcePlayer and stopped it from there.
i tried some solution, but nothing work.
i partial solved adding a thread sleep after WaitForStop
if (FinalVideo != null)
{
if (FinalVideo.IsRunning)
{
FinalVideo.SignalToStop();
Thread.Sleep(1000);
}
}
if i try to call Stop application will be freeze
I have a small project whereby I capture images from a webcam and decode the qr.
The following code captures an image and stores it to a local file, but only when it is not in the while loop. The system.threading appears to make the captured image just black. If i don't use it(the loop), it captures far too many images a second.
So is there a way of changing the aforge.video framerate so that i can capture an image every x seconds without while loop?
public partial class WebForm1 : System.Web.UI.Page
{
public int FrameRate { get; set; }
private FilterInfoCollection VideoCaptureDevices;
private VideoCaptureDevice FinalVideo;
protected void Page_Load(object sender, EventArgs e)
{
inputDevices.Items.Clear();
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
{
inputDevices.Items.Add(VideoCaptureDevice.Name);
}
inputDevices.SelectedIndex = 0;
}
public void Start_OnClick(object sender, EventArgs e)
{
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[inputDevices.SelectedIndex].MonikerString);
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.Start();
}
void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
int i = 0;
while (i < 10)
{
Bitmap video = (Bitmap)eventArgs.Frame.Clone();
video.Save("C:\\Users\\Wayneio\\Desktop\\image\\test" + i + ".jpg");
i++;
System.Threading.Thread.Sleep(5000);
}
}
public void Stop_OnClick(object sender, EventArgs e)
{
this.FinalVideo.Stop();
}
}
Additionally I get this error when trying to stop the capture via the asp button:
Object reference not set to an instance of an object on this.FinalVideo.Stop();
Tried this to no avail:
((VideoCaptureDevice)FinalVideo).DesiredFrameRate = 10;
before you code start video set the framreate like this
FinalVideo.DesiredFrameRate = 10;
FinalVideo.Start();
Another option to skip frames that you save is to use a function that is not always true
if you have a global counter value myCounter
do a modulo calulation like below ix mycounter devided by 10 equals 1
myCounter++
if (m(ycounter %% 10))==1) { //code to save your bitmap }