I am developing an app in which i want to capture images from a usb camera, i have seen many examples on the internet in which you have to initialize video first and then capture images from in using a button configured to do so. the problem is i want to capture the images without initializing the video first so it has to done be anonymously and then save it in some folder and write its location in database
any idea how it can be done?
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;
// Important: include the opencvsharp library in your code
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace Sandbox
{
public partial class Form1 : Form
{
// Create class-level accesible variables
VideoCapture capture;
Mat frame;
Bitmap image;
private Thread camera;
bool isCameraRunning = false;
// Declare required methods
private void CaptureCamera()
{
camera = new Thread(new ThreadStart(CaptureCameraCallback));
camera.Start();
}
private void CaptureCameraCallback()
{
frame = new Mat();
capture = new VideoCapture(0);
capture.Open(0);
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();
}
private void Form1_Load(object sender, EventArgs e)
{
}
// When the user clicks on the start/stop button, start or release the camera and setup flags
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text.Equals("Start"))
{
CaptureCamera();
button1.Text = "Stop";
isCameraRunning = true;
}
else
{
capture.Release();
button1.Text = "Start";
isCameraRunning = false;
}
}
// When the user clicks on take snapshot, the image that is displayed in the pictureBox will be saved in your computer
private void button2_Click(object sender, EventArgs e)
{
if (isCameraRunning)
{
// Take snapshot of the current image generate by OpenCV in the Picture Box
Bitmap snapshot = new Bitmap(pictureBox1.Image);
// Save in some directory
// in this example, we'll generate a random filename e.g 47059681-95ed-4e95-9b50-320092a3d652.png
// snapshot.Save(#"C:\Users\sdkca\Desktop\mysnapshot.png", ImageFormat.Png);
snapshot.Save(string.Format(#"C:\Users\sdkca\Desktop\{0}.png", Guid.NewGuid()), ImageFormat.Png);
}
else
{
Console.WriteLine("Cannot take picture if the camera isn't capturing image!");
}
}
}
}
I used Accord.net (AForge) for connect to the webcam and record video
But stored videos is slow motion ...
this my project :
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace CaptureWebcam
{
public partial class Form1 : Form
{
private VideoCaptureDeviceForm captureDevice;
private string path = Path.GetDirectoryName(Application.ExecutablePath) + #"\Videos\";
private FilterInfoCollection videoDevice;
private VideoCaptureDevice videoSource;
private VideoFileWriter FileWriter = new VideoFileWriter();
private Bitmap video;
bool isRecord = false;
public Form1()
{
InitializeComponent();
}
private void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
video = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();
}
private void btnStartCam_Click(object sender, EventArgs e)
{
videoDevice = new FilterInfoCollection(FilterCategory.VideoInputDevice);
captureDevice = new VideoCaptureDeviceForm();
if (captureDevice.ShowDialog(this) == DialogResult.OK)
{
videoSource = captureDevice.VideoDevice;
videoSource = captureDevice.VideoDevice;
videoSource.NewFrame += new NewFrameEventHandler(videoSource_NewFrame);
videoSource.Start();
timer1.Enabled = true;
}
//videoSource.DisplayPropertyPage(IntPtr.Zero);
}
private Thread workerThread = null;
private bool stopProcess = false;
private void recordLiveCam()
{
if (!stopProcess)
{
while (isRecord)
{
FileWriter.WriteVideoFrame(video);
}
FileWriter.Close();
}
else
{
workerThread.Abort();
}
}
private void btnRecord_Click(object sender, EventArgs e)
{
//try
//{
isRecord = true;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
int h = captureDevice.VideoDevice.VideoResolution.FrameSize.Height;
int w = captureDevice.VideoDevice.VideoResolution.FrameSize.Width;
FileWriter.Open(path + "recorded at " + DateTime.Now.ToString("HH-mm-ss") + ".mp4", w, h, 25, VideoCodec.MPEG4);
stopProcess = false;
workerThread = new Thread(new ThreadStart(recordLiveCam));
workerThread.Start();
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message);
//}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnStopRecord_Click(object sender, EventArgs e)
{
stopProcess = true;
isRecord = false;
FileWriter.Close();
workerThread.Abort();
video = null;
}
private void btnStopCam_Click(object sender, EventArgs e)
{
try
{
if (videoSource.IsRunning)
{
videoSource.SignalToStop();
videoSource.Stop();
pictureBox1.Image = null;
pictureBox1.Invalidate();
if (FileWriter.IsOpen)
{
FileWriter.Close();
video = null;
}
}
else
return;
}
catch
{
videoSource.Stop();
FileWriter.Close();
video = null;
}
}
float fts = 0.0f;
private void timer1_Tick(object sender, EventArgs e)
{
fts = videoSource.FramesReceived;
label1.Text = "Frame Rate : " + fts.ToString("F2") + " fps";
}
}
}
And when click the btnStopRecord following error :
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
"Slow motion" can have multiple reasons. First you need to know if the actual framerate, at which the NewFrames get produces is so slow (how many HZ then?) or if the CPU is too busy. Or the graphics card maybe.
For everything DirectShow related I strongly suggest using GraphEdit and AMCap to see what the real capabilites of the device are. AForge was prone to oversampling and I would not wonder if it's similar in Accord.
Also, you can always rely on good old processexplorer to see if the load (if any) is caused by SYSTEM or INTERRUPRS or is actually produced by your executable.
Another thing that happened to me was PictureBox. VideoSourcePlayer is far better and I wound up doing my own blitting.
It is worth mentioning these three optimizations:
DO NOT USE Bitmap.GetPixel!
Use videoSource.DisplayPinPropertyPage(IntPtr.Zero)
Check the color space of the videostream
Bitmap.GetPixel
The problem with GetPixel is, that it's really slow as it has to unmanage/manage a lot for every single pixel. It is fine as along as you only get a small a mount of calls and use it on a loaded bitmap. It is definately the wrong approach if you want to use it on all pixelx every couple of milliseconds. The CPU load from this phenomenon is associated with your application and will show as such in process explorer.
In the end I wrote my own pixel routines starting here: Work with bitmap faster with Csharp
If you just want a kernel or something more usual than I needed, implement a
custom Filter.
VideoSource.DisplayPinPropertyPage
If you use the AForge-buit-in mechanism for choosing the resolution and initiating the video stream, you cannot set the Framerate (I do not consider this a bug in AForge). So AForge always chooses the highest framerate. If you circumvent videoSource.VideoCapabilities and directly show the native device configuration dialog (it's formally called "Video Capture Pin Properties Dialog"). There you can set all the parameters manually and the dialog will fill in the appropriate framerate. This way, you will get the "real" (hardware) refresh rate in your callbacks. The CPU load of this oversampling happens in the SYSTEM process.
Color space conversion
In my case, the camera supports three output formats: YUY2, MJPG and RGB24. Depending on what format you use, the image is transformed by AForge into RGB (I think actually it's ARGB32). The rendered DirectShow graphs for all three formats are different and RGB obviously uses much less CPU than the others, as the color conversion is quite trivial. The load from this conversion also shows up in the SYSTEM process and not in your applications exe.
You can try to put some timers to understand which operation is slowing down the process.(Stopwatch class will be perfect)
I don't know the format of your Frame but usually the conversion to Bitmap is the bottle neck, AForge is quite fast. Furthermore you can pass a time stamp to WriteVideoFrame method, then the frame rate indicated in Open is just for replaying the video. Aforge will ordinate the frames in the right order with the right time.
That's according to my experience. Hope it can help.
Try this
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;
using AForge.Video.DirectShow;
using Accord.Video.FFMPEG;
using System.IO;
using AForge.Video;
using System.Threading;
namespace New_Project_2
{
public partial class Form1 : Form
{
private VideoCaptureDeviceForm captureDevice;
private FilterInfoCollection videoDevice;
private VideoCaptureDevice videoSource;
private VideoFileWriter FileWriter = new VideoFileWriter();
bool isRecord = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
if (isRecord == true)
{
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();
FileWriter.WriteVideoFrame((Bitmap)eventArgs.Frame.Clone());
}
}
catch (Exception)
{
throw;
}
}
private void button1_Click(object sender, EventArgs e)
{
videoDevice = new FilterInfoCollection(FilterCategory.VideoInputDevice);
captureDevice = new VideoCaptureDeviceForm();
if (captureDevice.ShowDialog(this) == DialogResult.OK)
{
isRecord = true;
int h = captureDevice.VideoDevice.VideoResolution.FrameSize.Height;
int w = captureDevice.VideoDevice.VideoResolution.FrameSize.Width;
FileWriter.Open("d:\\" + "recorded at " + DateTime.Now.ToString("HH-mm-ss") + ".mp4", w, h, 25, VideoCodec.MPEG4);
videoSource = captureDevice.VideoDevice;
videoSource.NewFrame += new NewFrameEventHandler(videoSource_NewFrame);
videoSource.Start();
}
//videoSource.DisplayPropertyPage(IntPtr.Zero)
}
private void button2_Click(object sender, EventArgs e)
{
}
private void button3_Click(object sender, EventArgs e)
{
isRecord = false;
FileWriter.Close();
}
private void button4_Click(object sender, EventArgs e)
{
}
}
}
You can use emguCV to record videos.
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;
using Emgu.CV;
using Emgu.CV.Structure;
namespace Load_Images
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
double TotalFrame;
double Fps;
int captureFrameNo;
VideoCapture capture;
VideoWriter writer;
bool isCapturing = false;
private void button1_Click(object sender, EventArgs e)
{
if (isCapturing == false)
{
capture = new VideoCapture(0);
TotalFrame = capture.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameCount);
Fps = capture.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps);
isCapturing = true;
int fourcc = fourcc = VideoWriter.Fourcc('H', '2', '6', '4');
capture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, 2048);
capture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, 1024);
//int fourcc = Convert.ToInt32(capture.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.FourCC));
int width = Convert.ToInt32(capture.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth));
int height = Convert.ToInt32(capture.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight));
string destin_path = "D:\\out.mp4";
writer = new VideoWriter(destin_path, fourcc, Fps, new Size(width, height), true);
capture.ImageGrabbed += Capture_ImageGrabbed;
capture.Start();
}
}
private void Capture_ImageGrabbed(object sender, EventArgs e)
{
try
{
if (isCapturing == true)
{
if (capture == null)
{
return;
}
Mat m = new Mat();
capture.Retrieve(m);
writer.Write(m);
pictureBox1.Image = m.ToImage<Bgr, byte>().Bitmap;
}
}
catch (Exception)
{
throw;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (isCapturing == true) {
capture.Stop();
isCapturing = false;
}
}
private void button3_Click(object sender, EventArgs e)
{
if (capture != null) {
capture.Pause();
}
}
private void button4_Click(object sender, EventArgs e)
{
if (writer.IsOpened)
{
isCapturing = false;
writer.Dispose();
}
MessageBox.Show("Completed");
}
private void Form2_Load(object sender, EventArgs e)
{
}
}
}
if you write file on newFrame handler Func will cause fastplaqy/slow record on some codec VP8-VP9 etc. (mpeg4 not effect) but if you start different timer on some time to write you solve your issues
First of all, I can't play and record HD video(1920x1080), when I change my camera resolution to 1920x1080 program show and record black background, if camera resolution is 720x576 it works without problems. I'm sure that the problem is in my solution because, when I use DesktopVideo(Software which is included with Blackmagic Decklink Studio 2) it shows HD video from camera.
Second, How do I convert video with AForge? like changing resolution and framerate, I can change codecs and bitrate, but when I change Resolution and FrameRate in "FileWriter.Open"
command I get Error Resolution and FrameRate must be the same as Bitmap I'm capturing from camera.
If anybody knows how to solve these problems please share information, thanks!
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.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
using AForge.Video.VFW;
namespace WindowsFormsApplication12
{
public partial class Form1 : Form
{
private FilterInfoCollection VideoCaptureDevices;
private VideoCaptureDevice FinalVideo = null;
private VideoCaptureDeviceForm captureDevice;
private Bitmap video;
//private AVIWriter AVIwriter = new AVIWriter();
private VideoFileWriter FileWriter = new VideoFileWriter();
private SaveFileDialog saveAvi;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
captureDevice = new VideoCaptureDeviceForm();
}
private void button1_Click(object sender, EventArgs e)
{
/////capture device list
if (captureDevice.ShowDialog(this) == DialogResult.OK)
{
VideoCaptureDevice videoSource = captureDevice.VideoDevice;
FinalVideo = captureDevice.VideoDevice;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.Start();
}
}
void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (butStop.Text == "Stop Record")
{
video = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();
//AVIwriter.Quality = 0;
FileWriter.WriteVideoFrame(video);
//AVIwriter.AddFrame(video);
}
else
{
video = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();
}
}
private void button2_Click(object sender, EventArgs e)
{
////record button
saveAvi = new SaveFileDialog();
saveAvi.Filter = "Avi Files (*.avi)|*.avi";
if (saveAvi.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
int h = captureDevice.VideoDevice.VideoResolution.FrameSize.Height;
int w = captureDevice.VideoDevice.VideoResolution.FrameSize.Width;
FileWriter.Open(saveAvi.FileName, w, h,25,VideoCodec.Default,5000000);
FileWriter.WriteVideoFrame(video);
//AVIwriter.Open(saveAvi.FileName, w, h);
butStop.Text = "Stop Record";
//FinalVideo = captureDevice.VideoDevice;
//FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
//FinalVideo.Start();
}
}
private void butStop_Click(object sender, EventArgs e)
{
if (butStop.Text == "Stop Record")
{
butStop.Text = "Stop";
if (FinalVideo == null)
{ return; }
if (FinalVideo.IsRunning)
{
//this.FinalVideo.Stop();
FileWriter.Close();
//this.AVIwriter.Close();
pictureBox1.Image = null;
}
}
else
{
this.FinalVideo.Stop();
FileWriter.Close();
//this.AVIwriter.Close();
pictureBox1.Image = null;
}
}
private void button3_Click(object sender, EventArgs e)
{
pictureBox1.Image.Save("IMG" + DateTime.Now.ToString("hhmmss") + ".jpg");
}
private void button4_Click(object sender, EventArgs e)
{
this.Close();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (FinalVideo == null)
{ return; }
if (FinalVideo.IsRunning)
{
this.FinalVideo.Stop();
FileWriter.Close();
//this.AVIwriter.Close();
}
}
}
}
The provided code simply captures and saves in the format currently active/selected for the capture device. In general, resolution change is an "expensive" operation is not available as a complimentary operation.
You want to change resolution right on capture device by switching it to more appropriate format, then capture in this resolution and have all further data manipulation in correct resolution. Available resolutions and options might be hardware specific there.
If/when no suitable capture resolution option is available, you typically resample the video to new resolution. Even though Windows API has suitable functionality, in your particular case you are interested to have this integrated with AForge library and you need to check its documentation to find out whether it provides a respective wrapper and whether it can be integrated into capture process overall (or, you need to write this code yourself to handle scaling).
how can i make a snapshot in my cod:
using DirectX.Capture;
using DShowNET;
private void Form1_Shown(object sender, EventArgs e)
{
DirectX.Capture.Capture capture = null;
Filters filters = null;
capture = new DirectX.Capture.Capture(filters.VideoInputDevices[deviceNo], filters.AudioInputDevices[0]);
capture.PreviewWindow = pictureBox1;
}
private void _Pause_Click(object sender, EventArgs e)
{
//??
}
i want to convert pictureBox1's video stream to a image by clicking on "Pause" button.
and then save pictureBox1's pic(*.jpg) to data base.
i want to play video in c#. i searched related tutorial and i found this. i followed exactly the same but the video would not appear.
here is 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.Windows.Forms;
using Microsoft.DirectX.AudioVideoPlayback;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
Video video;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// store the original size of the panel
int width = panel1.Width;
int height = panel1.Height;
// load the selected video file
//video = new Video("C:\\Users\\HDAdmin\\Desktop\\Example.avi");
video = new Video(openFileDialog1.FileName);
// set the panel as the video object’s owner
video.Owner = panel1;
// stop the video
video.Stop();
// resize the video to the size original size of the panel
panel1.Size = new Size(width, height);
try
{
video.Audio.Volume = 100;
}
catch { }
}
}
private void button2_Click(object sender, EventArgs e)
{
if (video.State != StateFlags.Running)
{
video.Play();
}
}
private void button3_Click(object sender, EventArgs e)
{
if (video.State == StateFlags.Running)
{
video.Pause();
}
}
private void button4_Click(object sender, EventArgs e)
{
if (video.State != StateFlags.Stopped)
{
video.Stop();
}
}
}
}
i even tried to put a path of the video like this:
video = new Video("C:\\Users\\HDAdmin\\Desktop\\Example.avi");
but both of it will show the error like picture below.
my question is, how i want to enable to view and play the video by using windows form application in c#?
p/s: i want to use Directx only and do not want to play the video in windows media player.