I´m using class Capture from EmguCV to take images from a WebCam.
According to the documentation of the class (http://www.emgu.com/wiki/files/2.0.0.0/html/18b6eba7-f18b-fa87-8bf2-2acff68988cb.htm), Capture has 3 constructors.
Using public Capture() its supposed to use the default camera and it works properly.
As I saw in one of the examples, seems that
public Capture(string fileName) //takes a video file as the source for the captures.
The last constructor is
public Capture(int camIndex) //which is supposed to "Create a capture using the specific camera"
I tried to use this last constructor to allow the user to choose the device in case he has more than one camera (for example, the integrated camera in a laptop or a USB cam pluged in)
My problem is I don´t know how to get a list of available devices. Tried to create captures with index from 0 to 99 and try to grab a frame expecting an exception, but it just takes a black image with the 100 captures. Also, when I use the default camera, I don´t know how to get his index.
Any help?
Edit: With the info in the answer of Shiva I got it working with this (I post it for future references):
private void onLoad(object sender, RoutedEventArgs e)
{
//Add the image processing to the dispatcher
this.Dispatcher.Hooks.DispatcherInactive += new EventHandler(dispatcherTimer_Tick);
//Get the information about the installed cameras and add the combobox items
DsDevice[] _SystemCamereas = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
Video_Device[] WebCams = new Video_Device[_SystemCamereas.Length];
for (int i = 0; i < _SystemCamereas.Length; i++)
{
WebCams[i] = new Video_Device(i, _SystemCamereas[i].Name, _SystemCamereas[i].ClassID); //fill web cam array
ComboBoxDevices.Items.Add(WebCams[i].ToString());
}
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (capture != null)
{
//Capture an image
Image<Bgr, byte> img = capture.QueryFrame();
//Show the image in the window
ImageOriginal.Source = ImageProcessor.ToBitmapSource(img);
}
}
private void ComboBoxDevices_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//If there is already a capture, dispose it
if (capture != null)
{
capture.Dispose();
}
//Get the selected camera
int selectedDevice = ComboBoxDevices.SelectedIndex;
try
{
//Create new capture with the selected camera
capture = new Capture(selectedDevice);
}
catch (Exception excpt)
{
MessageBox.Show(excpt.Message);
}
}
The capture object can be used to give static files as input using the following code
Capture grabber = new Emgu.CV.Capture(#".\..\..\file.avi");//can be relative path or absolute path of the video file.
For finding the list of connected web cams will need to import something like Direct Show (DirectShow.Net.dll) into the project and use the following code to retrieve the list of connected web cams .
DsDevice[] _SystemCamereas = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
Video_Device[] WebCams = new Video_Device[_SystemCamereas.Length];
for (int i = 0; i < _SystemCamereas.Length; i++)
{
WebCams[i] = new Video_Device(i, _SystemCamereas[i].Name, _SystemCamereas[i].ClassID); //fill web cam array
Camera_Selection.Items.Add(WebCams[i].ToString());
}
Check this link for the full code
http://www.emgu.com/wiki/index.php?title=Camera_Capture
This list can be populated into a combo box and each connected device can be chosen to retrieve the video input from the specific device.
Example can be found here:
http://fewtutorials.bravesites.com/entries/emgu-cv-c/level-2---use-multiple-cameras-in-one-application.
For your last question the Default Camera always has the index of 0.
So for initializing the Capture Object with default camera you will have to use the following code
Capture grabber = new Emgu.CV.Capture(0);
Examining the EMGU CV source seems to indicate that it's just passing the index off to the underlying OpenCV library, as part of the cvCreateCameraCapture (int index) function. That function is... A bit of a mess of #ifdefs, but from what I can see (and from what the comments indicate), the index is used to specify both the camera you want, and the API it should be using.
Try successively trying multiples of a hundred; each should use a different codec, attempting to use the first camera. It may be that you have one of the APIs listed compiled into your copy of OpenCV, but not working correctly on your system.
Edit: Drilling down further, it seems like it ends up at this function call, which uses the MFEnumDeviceSources function to get the list. The device you wanted is then returned out of that list (see the getDevice function a few lines higher up). So, it looks to me like the dialog you mentioned in your comment is part of Windows' MediaFoundation stuff, in which case you might want to google the wording of the message, see if some people with more experience with MF can point you in the right direction.
Related
I've been stuck on this all day, so I'm going to post everything I've been able to find today that might be useful to helping me, it will be a long post. I'm having 2 issues that I believe are related to the same problem. First, let me explain what I am doing. I have 3 Winforms combo boxes that are bound to lists of all of the devices found by MMDeviceEnumerator. Two output device boxes, one input device. I am using the MMDeviceEnumerator to register a callback for whenever the devices are changed, removed, or a default device is set. The callback fires an event that then invokes a delegate to the form thread to re-enumerate the devices into combo boxes. It looks like this:
public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
{
Devices.OnDevicesUpdated();
}
//The handler called by this event:
private void UpdateDeviceSelectors(object? sender = null, EventArgs? e = null)
{
Invoke(delegate ()
{
int primaryIndex = Devices.PrimaryOutput + 1, secondaryIndex = Devices.SecondaryOutput + 2, microphoneIndex = Devices.Microphone + 1;
Devices.Refresh();
try
{
SecondaryOutputComboBox.SelectedIndex = secondaryIndex;
PrimaryOutputComboBox.SelectedIndex = primaryIndex;
MicrophoneSelectComboBox.SelectedIndex = microphoneIndex;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
});
}
Now for the two issues I have. The first one involves a semi-random crash that leads back to NAudio.Wasapi.dll, where a System.ExecutionEngineException is thrown. It is kind of easy to reproduce. All I do is change the values of the combo boxes, switch the default devices around, and it will randomly crash.
The second issue occurs when another part of my code is involved. I have a microphone injector, which redirects a WaveInEvent that records a selected input device to a WaveOutEvent, like a loopback. Here is the relevant code for this:
public void Start()
{
if (Soundboard.Devices.SecondaryOutput == -2) return;
micStream = new WaveInEvent();
micStream.BufferMilliseconds = 50;
micStream.WaveFormat = new WaveFormat(44100, WaveIn.GetCapabilities(Soundboard.Devices.Microphone).Channels);
micStream.DeviceNumber = Soundboard.Devices.Microphone;
WaveInProvider waveIn = new(micStream);
var volumeSampleProvider = new VolumeSampleProvider(waveIn.ToSampleProvider());
volumeSampleProvider.Volume = 1 + Settings.Default.MicrophoneGain;
virtualCable = new WaveOutEvent();
virtualCable.DesiredLatency = 150;
virtualCable.DeviceNumber = Soundboard.Devices.SecondaryOutput;
virtualCable.Init(volumeSampleProvider);
micStream.StartRecording();
virtualCable.Play();
}
public void Stop()
{
try
{
if (micStream != null && virtualCable != null)
{
micStream.Dispose();
micStream = null;
virtualCable.Dispose();
virtualCable = null;
}
}
catch
{
micStream = null;
virtualCable = null;
}
}
In the delegate mentioned earlier, I am calling the Stop method of the Mic Injector and then the Start method to refresh the WaveIn and WaveOut devices to use the current device numbers so users do not see a device selected when a different device is being used. When this happens, the program, rather than crashing instantly and inconsistently, always hangs and has to be killed from the task manager. I am certain these 2 problems are related to the same root cause, but I have no idea what that root cause may be. Switching to Wasapi, DirectSound, or ASIO won't work because they lack certain functionalities I need, so I would really like to get this working still using Wave streams.
I've tried to find different ways to detect the device changes, assuming it is an issue deep inside NAudio, but I just can't find anything else. For the second problem specifically, I have moved the calls to the Mic Injector around thinking it may be a threading issue or something, but it didn't work or change the behavior.
I've got a little problem with ZXing.net... I dosen't work !
Maybe I use it incorrectly, but I search, search, search, nothing seems to work... I use WindowsForms. I want to read my QR Code thought my camera. I use another library called AForge. This one works perfectly ; My camera shows up and works like a charm ! But when I want to read a QR Code, it dosen't work...
So maybe someone will be able to help me ... ?
//When I load my form, I start the camera
private void FrmConnexion_Load(object sender, EventArgs e)
{
// enumerate video devices
videoSources = new FilterInfoCollection(FilterCategory.VideoInputDevice);
// create video source
videoStream = new VideoCaptureDevice(videoSources[0].MonikerString);
// set NewFrame event handler
videoStream.NewFrame += new NewFrameEventHandler(videoSource_NewFrame);
// start the video source
videoStream.Start();
}
//Every new frame of the video
void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
streamBitmap = (Bitmap)eventArgs.Frame.Clone();
safeTempstreamBitmap = (Bitmap)streamBitmap.Clone();
Pic_Camera.Image = streamBitmap;
Pic_Camera.Refresh();
//Where I decome my QR Code.
Result result = barcodeReader.Decode(streamBitmap);
//To see my result, I register my result into a Label.
Lbl_Identifiant.Text = "{result?.Text}";
}
catch (Exception exp)
{
Console.Write(exp.Message);
}
}
I think I didn't forget anything..
Thanks for your help !
So I'm totally new to C# and I've been building a "Character Generator" for a tabletop RPG. I've assigned a button with the task of generating a new story every time it is pressed. I've downloaded a huge collection of character portraits which I'd like to display in this little app of mine to give some inspiration to the user.
I thought that using a button I could have the app select a different image in the aforementioned list every time it is pressed.
I tried this:
private void button1_Click(object sender, EventArgs e)
{
List<String> paths = new List<String>();
Random random = new Random();
paths.Add(Project1.Cartes.Portrait);
pictureBox1.ImageLocation = paths[random.Next(0, images.Count - 1)];
I get two errors: Project1.Cartes.Portrait is an invalid namespace, and the name "images" does not exist.
I can't mention every image, since there are 500 of them. So I need the app to instead take a random image from a specific location. Any ideas ?
There is insufficient code be definite, however, the errors do indicate exactly what's wrong. For example, where is the variable images defined, what type is it, and how it is initialised? Also, I assume that Project1.Cartes.Portrait is meant to be a list of paths to the images and should there for be defined as List<string> somewhere within the current namespace.
As I noted in my comment, I think the Project1.Cartes.Portrait is not what you expect it to be. It should be a List<string> to any image files on your disk but it might add the string representation to your paths list.
Something like:
System.Collections.Generic.List1[System.String] (which is definitively not a path to an image file)
instead of the expected:
C:\mypath1.jpg
C:\mypath2.jpg
C:\mypath3.jpg
So please stop the debugger with a breakpoint after paths.Add(Project1.Cartes.Portrait) and check if your variable paths is what you expect it to be.
Btw, if Project1.Cartes.Portraitpoints to a real List<string>, you should use paths.AddRange(...) instead of paths.Add(...) to add the string contents from the list instead of the list itself.
Store the image's locations while your form is loading. Also, you need to remove image use bellow instead.
pictureBox1.ImageLocation = paths[random.Next(0, paths.Count - 1)];
Here is the full code. Just need to store the file names in the list.
List<String> paths = new List<String>();
private List<string> GetPaths()
{
//You can get it anywhere
throw new NotImplementedException();
}
private void Form1_Load(object sender, EventArgs e)
{
paths = GetPaths();
}
private void button1_Click(object sender, EventArgs e)
{
Random random = new Random();
pictureBox1.ImageLocation = paths[random.Next(0, paths.Count - 1)];
}
How to upload or add an Image to UIImageView directly from iPhone/Ipad Captured camera Image.
I have uploaded an image to UIImageView from photo library.
Now, I want upload an image directly after taken an image through camera to ImageView.
Please suggest me how to implement this.
using IOS 8.0
This can be accomplished very easily with the Xamarin.Mobile component, which is free and works with all platforms.
http://components.xamarin.com/view/xamarin.mobile
From the example they give:
using Xamarin.Media;
// ...
var picker = new MediaPicker ();
if (!picker.IsCameraAvailable)
Console.WriteLine ("No camera!");
else {
try {
MediaFile file = await picker.TakePhotoAsync (new StoreCameraMediaOptions {
Name = "test.jpg",
Directory = "MediaPickerSample"
});
Console.WriteLine (file.Path);
} catch (OperationCanceledException) {
Console.WriteLine ("Canceled");
}
}
After you take the picture, it is saved to the directory you specified, with the name you specified. To easily retrieve this picture and display it with your ImageView using the above example you can do the following:
//file is declared above as type MediaFile
UIImage image = new UIImage(file.Path);
//Fill in with whatever your ImageView is
yourImageView.Image = image;
Edit:
Just a note that the above needs to be asynchronous. So if you want to launch the camera from a button call, for instance, you just slightly modify the .TouchUpInside event:
exampleButton.TouchUpInside += async (object sender, EventArgs e) => {
//Code from above goes in here, make sure you have async after the +=
};
Otherwise you could wrap the code from above in a function and add async to that:
public async void CaptureImage()
{
//Code from above goes here
}
You will need to use AVFoundation to do this. Check out the AVCam sample project in Xcode:
https://developer.apple.com/library/ios/samplecode/AVCam/Introduction/Intro.html
I am debugging a WCF project with two-way communication. I have a callback with data that I store in an array the client, a WinForm, and use that for painting a control. As you can guess, the data disappears from writing in the array (really a list) to when I read the data.
For debugging I would like to see if I am writing and reading the same object so that the callback function isn't making some kind of copy and throw it away. For example I want to see the address of the this - pointer. How do I do that in VS2010 Exp?
Edit
Some code:
Field declaration:
// the cards that the player have
private List<Card> cards = new List<Card>();
callback handler:
private void btnDraw_Click(object sender, EventArgs e)
{
Tuple<Card, string> update = PressedDraw(this);
cards.Add(update.Item1);
PaintCards();
}
paint event:
private void cardPanel_Paint(object sender, PaintEventArgs e)
{
int counter = 0;
Point fromCorner = new Point(20,12);
int distance = 50;
foreach (Card card in cards)
{
Point pos = fromCorner;
pos.Offset(counter++ * distance, 0);
Bitmap cardBitmap =
cardFaces[Convert.ToInt32(card.suit),
Convert.ToInt32(card.rank)];
Rectangle square = new Rectangle(pos, cardBitmap.Size);
e.Graphics.DrawImage(cardBitmap, square);
}
When I debug I enter first in the callback handler and adds a Card in cards
PaintCards() calls Invalidate and the paint event is run. When in cardPanel_Paint, cards.Count is zero again.
Best regards.
Görgen
In the Watch/Locals/Autos windows, you can right-click on an object and select "Make Object ID" to give the object an identification number. This number is effectively the same as a native object's address; it serves to identify.
The identity of an object is tracked across garbage collections and compactions, so across the lifetime of your application, you can tell if a certain object is the one you originally tagged. This feature might help in your situation.
This blog post has a quick run-through of the feature.
The address of an object in c# can be changed by the garbage collector so you can not use that (and there is no straight forward method to do so).
But you can use Object.ReferenceEquals to compare to objects to see if they are really the same.
Edit:
But it looks like you have messed things up something like this.
var a = new List<string> { "String1" };
var b = a;
a = new List<string> { "String 2" }; // really GetListFromWcf();
Console.WriteLine(b[0]);
this prints String1, not String2.
If you can not figure it out you need to post some code to show where thing get wrong.