using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
namespace WebcamTest
{
public partial class Form1 : Form
{
private Capture c;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
c = new Capture();
c.ImageGrabbed += ProcessFrame;
c.Start();
}
public void ProcessFrame(object sender, EventArgs e)
{
Image<Bgr, byte> image = c.QueryFrame();
c.ImageGrabbed -= ProcessFrame;
c.Stop();
c.Dispose();
}
}
}
So I have this really simple code to grab a webcam image and store it, just one time. It does nothing else currently, but I'm having a weird issue. In my file, one line seems to cause the issue:
Image<Bgr, byte> image = c.QueryFrame();
EDIT: I have tried changing this line to this as the wiki suggests:
Image<Bgr, byte> image = new Image<Bgr, byte>(c.RetreiveBgrFrame().ToBitmap());
This one always gives a null reference exception the first time; afterwards it acts the same as the other line. Every pixel's combined values are 0's after the first run.
Then I go a bit deeper into the problem,
I found that I keep getting a StackOverflowException in the Emgu.CV.dll itself. It continously says it is line 240 in this file: Capture.cs
The line is this:
bool grabbed = CvInvoke.cvGrabFrame(_ptr);
I have ran through their examples before and actually had them working before. I have never really had this issue before since it's coming from inside their dll. Why would this line keep causing this error? Is the pointer way off point for some unknown reason? The only thing I could think was that it was trying to access a memory location outside the actual bounds. It's always the very first run it does this. Then when it crashes, the camera stays on and so next time it runs. Though the image pixels are all 0's every time after that.
Related
I have written C# code of live streaming of IP camera (JPEG) in windows form application using AForge library. It is working but it's lagging too much.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AForge.Video;
namespace CCTV_software
{
public partial class Form1 : Form
{
JPEGStream stream;
JPEGStream stream1;
public Form1()
{
InitializeComponent();
stream = new JPEGStream("ip");
stream1 = new JPEGStream("ip1");
stream.Login = "username";
stream.Password = "password";
stream1.Login = "username1";
stream1.Password = "password1";
stream.NewFrame += stream_NewFrame;
stream1.NewFrame += stream1_NewFrame1;
stream.Start();
stream1.Start();
}
void stream_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bmp = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = bmp;
}
void stream1_NewFrame1(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bp = (Bitmap)eventArgs.Frame.Clone();
pictureBox2.Image = bp;
}
}
Tried adding:
stream.FrameInterval = 0;
But it didn’t made any difference.
Kindly help me out with this issue.
Edit:
Edit 2:
#mjwills and my suggestions combined:
void stream_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
var oldImage = pictureBox1.Image
pictureBox1.Image = eventArgs.Frame; // set to new image without making a copy
oldImage?.Dispose(); // = Dispose previous image, if not null
}
This spares you a clone which is expensive and allows the gc to clean up the images timely.
Those measures combined should make it possible to improve throughput (i.e. lessen "lag"). Further countermeasures could be to make the image size smaller or reduce quality ...
NOTE: Above measures should at least improve lag, yet it is not guaranteed to make it disappear completely, since lag may be caused at other places, too.
I use a GD4430 handheld scanner from the company Datalogic with the included OPOS driver. With the following code I manage to address the scanner. When I start the program, the scanner becomes active and you can scan. But I can not display the results in a TextBox.
Does anyone see where the error lies?
Visual Studio 2010 C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestRead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
axOPOSScanner1.BeginInit();
axOPOSScanner1.Open("USBHHScanner");
axOPOSScanner1.ClaimDevice(0);
axOPOSScanner1.DeviceEnabled = true;
axOPOSScanner1.DataEventEnabled = true;
axOPOSScanner1.PowerNotify = 1; //(OPOS_PN_ENABLED);
axOPOSScanner1.DecodeData = true;
}
void axOPOSScanner1_DataEvent(object sender, AxOposScanner_CCO._IOPOSScannerEvents_DataEventEvent e)
{
textBox1.Text = axOPOSScanner1.ScanDataLabel;
textBox2.Text = axOPOSScanner1.ScanData.ToString();
axOPOSScanner1.DataEventEnabled = true;
axOPOSScanner1.DataEventEnabled = true;
}
}
}
Was not the processing of AxOPOSScanner1.BeginInit() on the source originally in Form1.Designer.cs instead of here?
(I am assuming that the source file name is Form1.cs)
As below(in Form1.Designer.cs):
this.axOPOSScanner1 = new AxOposScanner_CCO.AxOPOSScanner();
((System.ComponentModel.ISupportInitialize)(this.axOPOSScanner1)).BeginInit();
this.SuspendLayout();
There is a possibility that the problem has occurred because you moved it to Form1.cs or calling BiginInit() on both Form1.Designer.cs and Form1.cs.
Or, the following processing does not exist in Form1.Designer.cs, or there is a possibility that the specified function name(axOPOSScanner1_DataEvent) is wrong.
this.axOPOSScanner1.DataEvent += new AxOposScanner_CCO._IOPOSScannerEvents_DataEventEventHandler(this.axOPOSScanner1_DataEvent);
In addition:
What you should do is to temporarily store the return value of all the methods, add a process to determine whether the method was executed normally, likewise It is to read the ResultCode property immediately after setting the property(possibly causing an error) and add processing to judge whether the property setting was done normally.
Also, although not related to DataEvent, PowerNotify setting must be done before DeviceEnabled = true.
So I'm trying to make a simple program in Visual C# that counts the number of "Connected Devices", which can be seen as the amount of buttons clicked.
The code should check which button was clicked and change it's background image. It should also update the count and label on the form.
First of all, here's my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Device_Storage
{
public partial class Form1 : Form
{
int totalDevices = 0;
public Form1()
{
InitializeComponent();
}
private void addDevice(object sender, EventArgs e)
{
try
{
Button clickedBtn = sender as Button;
Image add_image = Properties.Resources.addDevice;
Image remove_image = Properties.Resources.removeDevice;
if (clickedBtn.BackgroundImage == Properties.Resources.addDevice)
{
clickedBtn.BackgroundImage = remove_image;
totalDevices++;
}
else if (clickedBtn.BackgroundImage == Properties.Resources.removeDevice)
{
clickedBtn.BackgroundImage = add_image;
totalDevices--;
}
updateLabel();
} catch (Exception ex)
{
MessageBox.Show(ex.Message, "An Error Occured");
}
}
private void updateLabel()
{
label1.Text = "Connected devices: " + totalDevices;
}
}
}
(I didn't change any of the using statements yet, I usually do that when I'm finished or am 100% sure I won't be using the namespace)
I can't find anything wrong with the code myself and Visual Studio (2015) doesn't give an error.
When I click a button (there are 36 total buttons) nothing happens, the label doesn't update, the image doesn't change, nothing. I don't even get an error, the program doesn't crash.
If anyone can see what I did wrong and can help me fix it that would be really appreciated.
(Edit: My resources folder contains 2 png files, "addDevice.png" and "removeDevice.png")
(New info: all buttons start with the background image "addDevice.png" as to represent an empty slot)
everyone. I have been stuck here dealing with this bugs for days, but I still couldn't figure it out.
My guess: I think my code has some problem as I did not dispose the object properly after using it, (I'm not very familiar with these concepts of releasing resources, threading) .
I got these code by taking reference of what people did on youtube, but despite me doing exactly the same thing, my code didn't work out nicely.
SITUATION:
I have two picture boxes, left one can take video of me, right one take the snapshot, if you press button1 , you will start the video, clone_button will copy a image i.e. take a snapshot, and save_image should save it to the path reference, however, i get a generic error occured in GDI+ again and again while I'm trying to save it. Also, my debugger seemed to get crazy (i.e. failed to terminate the vshost.exe ) once I ran this program, I have to restart the computer to get my code running again, which is bleak and frustrating.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
//AForge.Video dll
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge;
namespace WebCameraCapture
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private FilterInfoCollection CaptureDevice; // list of webcam
private VideoCaptureDevice FinalFrame;
private void Form1_Load(object sender, EventArgs e)
{
CaptureDevice = new FilterInfoCollection(FilterCategory.VideoInputDevice);//constructor
foreach (FilterInfo Device in CaptureDevice)
{
comboBox1.Items.Add(Device.Name);
}
comboBox1.SelectedIndex = 0; // default
FinalFrame = new VideoCaptureDevice();
}
private void button1_Click(object sender, EventArgs e)
{
FinalFrame = new VideoCaptureDevice(CaptureDevice[comboBox1.SelectedIndex].MonikerString);// specified web cam and its filter moniker string
FinalFrame.NewFrame += new NewFrameEventHandler(FinalFrame_NewFrame);// click button event is fired,
FinalFrame.Start();
}
void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs) // must be void so that it can be accessed everywhere.
// New Frame Event Args is an constructor of a class
{
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();// clone the bitmap
}
private void From1_CLosing(object sender, EventArgs e)
{
if (FinalFrame.IsRunning==true) FinalFrame.Stop();
}
private void save_Click(object sender, EventArgs e)
{
if (pictureBox2.Image != null)
{
Bitmap varBmp = new Bitmap(pictureBox2.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Dispose();
varBmp = null;
varBmp.Save(#"C:\a.png", ImageFormat.Png);
}
else
{ MessageBox.Show("null exception"); }
}
private void clone_Click(object sender, EventArgs e)
{
pictureBox2.Image = (Bitmap)pictureBox1.Image.Clone();
}
}
}
Any AForge.net user can just PRESS the LINK below and try it out. Thanks!
SAMPLE
After having a look at your code, to me it appears that you are disposing of your image right before you save it. Meaning that your program can't save the image, because it doesn't exist anymore. Actually it reads that you've essentially removed the captured image twice, once on dispose, the second when you set it as null.
So if you move the two code segments after the save, it should be working. Granted without using a dialog box to change the name of the file, you'll surely receive an error unless you remove that file after each time it has been created.
private void save_Click(object sender, EventArgs e)
{
if (pictureBox2.Image != null)
{
//Save First
Bitmap varBmp = new Bitmap(pictureBox2.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Save(#"C:\a.png", ImageFormat.Png);
//Now Dispose to free the memory
varBmp.Dispose();
varBmp = null;
}
else
{ MessageBox.Show("null exception"); }
}
If you open the task manager, you can watch how much memory your program is soaking up.
Disposing of the memory after you're done using it, gives it back to the system.
You don't have a dispose inside your FinalFrame_NewFrame thread, so when the camera is reading images,
you should see the memory usage continue to climb until you stop the program.
I've added dispose to my thread, putting the memory usage under control, but now I'm debugging my image saves. Because I'm disposing, I can't save the image lol. My program ends up trying to save a null image file and throws the appropriate error.
I'm using a 2nd picurebox just as you are, but using for example, pbox2.image = pbox1.image, doesn't copy the data, it copies the memory location with the image data, so when I dispose pbox1 to free memory, the image data disappears with the memory location.
So, I had the same issue, and it was resolved one, by moving the dispose method, and two, I had to change the path, it didnt want to save to C:, so I put it on my desktop, you may not have had this issue if you were running as admin but I did so for anyone else who sees this, dont save to the root of C:.
I'm a newbie in emgu cv and for a major project I'm trying to capture an image from a webcam and show it in an image box, but it's showing a black image.
What is wrong with the following code?
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using Emgu.Util;
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
private Capture capture;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
if (capture == null)
capture = new Capture();
Image<Bgr,Byte> img=capture.QueryFrame();
imageBox1.Image = img;
}
}
}
I think there is a minor mistake.
Use this instead:
Declare as global variable:
Capture capture = default(Capture);
Put this in load:
capture = new Capture(0);
Control.CheckForIllegalCrossThreadCalls = false;
System.Threading.Thread t = new System.Threading.Thread(grab);
t.Start();
Create a sub grab and put in,
do {
ImageBox1.Image = capture.QueryFrame();
} while (true);
Cheers
Shreyas
Call QueryFrame() twice, it works for me:
if (capture == null)
capture = new Capture();
capture.QueryFrame();
Image<Bgr,Byte> img=capture.QueryFrame().ToImage<Bgr, Byte>();
imageBox1.Image = img.Bitmap;
In my case Kaspersky AntiVirus was blocking the access to my webcam. After changing some security settings I was able to get emgu capture back working.