I'm building a test application in C# to detect faces from a webcam and
I've built it as a Windows Form with a Timer (timer1), a Picture Box for displaying the webcam output (pictureBox1) and a Textbox for displaying the number of faces (textBox2). I have installed EmguCV through NuGet (v3.1.0.1) and set everything up. Most of the tutorials for EmguCV are for an earlier version, and the necessary HaarCascade class has been depreciated. However, this Stack Overflow question provided me with the necessary updates to my code.
I now have everything set up to work. The webcam displays an updating image in pictureBox1. The detector is supposed to work on the webcam frames every time timer1 ticks over, and the number of rectangles in the Faces[] array is outputted as a string to textBox2. However, nothing seems to be working. I cannot get it to recognise anything. The program is running, but the number of faces detected always says 0. If I initially set the NumberOfFaces variable to something like 5, the Emgu code changes it to 0 in the output. So, something is happening. I'm using the haar xml provided with EmguCV, but no avail. Can anybody help me?
Code dump below:
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;
using Emgu.Util;
using Emgu.CV.CvEnum;
namespace FaceDetectTest
{
public partial class Form1 : Form
{
public Capture cap;
public CascadeClassifier haar;
public int NumberOfFaces;
public Rectangle[] Faces;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
cap = new Emgu.CV.Capture(0);
haar = new CascadeClassifier(#"C:\Users\Rob\AppData\Roaming\masterbeast\haarcascade_frontalface_alt_tree.xml");
NumberOfFaces = 0;
}
private void timer1_Tick_1(object sender, EventArgs e)
{
using (Image<Bgr, byte> nextFrame = cap.QueryFrame().ToImage<Bgr, Byte>())
{
if (nextFrame != null)
{
Image<Gray, byte> grayframe = nextFrame.Convert<Gray, byte>();
Faces = haar.DetectMultiScale(grayframe, 1.1, 1, new Size(100, 100), new Size(1000, 1000));
NumberOfFaces = Faces.Length;
}
pictureBox1.Image = nextFrame.ToBitmap();
textBox2.Text = NumberOfFaces.ToString();
}
}
}
}
As so often with Stack Overflow, I found a (partial) solution to this some seconds after posting the question.
What seemed to be causing the issue was the conditional statement if (nextFrame != null). I don't know if this has to do with the refresh rate of my webcam, or the timer1 tickover. Removing this now detects faces, though I need to play around with the parameters of the DetectMultiScale method as they only are detected if fully face-on and very close.
If anybody can shed any light on this further, please be my guest; however, it works, and that is all that matters to me. If you are coming here for an example of using Emgu.CV 3.1 for face detection, try the above code without that conditional statement.
Related
I have two winforms in my application. One of the forms has a picturebox with a jpg loaded of our building plan. The main form has code that does facial recognition identifying people coming into certain areas. I have been asked to modify this program to show an identified individual's location on the building plan. I have a database that has all the X,Y coordinates of the locations that should map to the building plan image. I have looked around and tried to find some code that will draw a circle on the map at the X,Y coordinates as the person progresses through areas of the building by erasing all the existing circles and updating this new one. So on the map form I put in the following code:
public void DrawCircle(int x, int y)
{
Graphics gf = pictureBox1.CreateGraphics();
gf.DrawEllipse(new Pen(Color.Red), new Rectangle(x, y, 400, 400));
pictureBox1.Refresh();
}
Then from the update method (right now a button click for testing) on the main form I call this method on the map form. The method gets called, but the circle doesn't show up on the form. I have tried both Refresh and Invalidate and neither method seems to draw the circle on the image.
I haven't done winforms development for years, so I'm sure I am missing some plumbing somewhere. Here is the code on the mainform:
LocationMap map = new LocationMap();
public Form1()
{
InitializeComponent();
//set up signalR
UserName = "MovementHub1";
ConnectAsync();
//show the map screen
map.Show();
map.WindowState = FormWindowState.Maximized;
...
Then in a click event (for testing right now) I have this code:
private void button2_Click(object sender, EventArgs e)
{
map.DrawCircle(340, 258);
}
Once I get the circle drawn on the other form, then I will remove the code from the click event and move it another event that does the updating on the location. If it's possible, I would like to put a label by the circle that has the person's name. Right now this is a proof of concept, I just need help getting the circle on the form to start with.
Thanks.
I tried It out by myself and came up with that:
Form1.cs
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 StackoverflowHelp
{
public partial class Form1 : Form
{
Form2 form = new Form2();
public Form1()
{
InitializeComponent();
form.Show();
}
private void Button1_Click(object sender, EventArgs e)
{
form.DrawCircle(100, 100);
}
}
}
Form2.cs
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 StackoverflowHelp
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
DrawCircle(10, 10);
}
public void DrawCircle(int x, int y)
{
Graphics gf = Graphics.FromImage(pictureBox1.Image);
gf.DrawEllipse(new Pen(Color.Red), new Rectangle(x, y, 20, 20));
gf.Dispose();
pictureBox1.Refresh();
pictureBox1.Invalidate();
pictureBox1.Update();
}
}
}
Instead of calling CreateGraphics() on the picturebox I created the graphics object using the current image.
I'm working with C#, só I start one "Windows Form application" in order to use the "picturebox", where I can draw some things. I would like to know if there's a way to save a file in some kind of file (like JPG). Here's an example, where I draw a simple line in a pictureBox with 300 of Height and 300 of Width.
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 AskStack
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Here I declare 'MyDraw' and a Pen that I'm gonna use
Graphics MyDraw;
Pen BluePen = new Pen(Color.Blue, 10);
// What happens when I click in my button
private void ButtonDraw_Click(object sender, EventArgs e)
{
MyDraw.Clear(Color.White);
// Here I relate MyDraw to the pictureBox that I have in my Form
MyDraw = pictureBox1.CreateGraphics();
// Here I Just draw a simple line
MyDraw.DrawLine(BluePen, 25, 25, 80, 80);
// I don't know exactly what this does
MyDraw.Save();
}
}
}
I would like to know if there's a way to save this image in a file where I can easily acess it. Also, I would like to know if there's a way to save an JPG file and dimension the file's size WITHOUT using a pictureBox. Thanks!!!
You can try with this line of code:
pictureBox1.Image.Save(#"Path",ImageFormat.Jpeg);
So I'm working on a little app to recognize faces as people walk into my room in order to shout things at them (Mature, I know).
Problem is, I have the face recognition recognizing faces, but drawing it to the screen is being problematic. Strictly speaking, it does not need to draw anything to the screen, but I just want to see it working.
Form1.cs
using System;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.UI;
using Emgu.CV.Structure;
using System.Threading;
using System.Drawing;
namespace OpenCVApp1 {
public partial class Form1 : Form {
ImageViewer viewer = new ImageViewer(); //create an image viewer
private Capture cap = new Capture(0);
private CascadeClassifier cascade = new CascadeClassifier("..\\..\\Resources\\haarcascade_frontalface_alt2.xml");
Thread camWorker;
public Form1() {
InitializeComponent();
Application.ApplicationExit += Application_ApplicationExit;
cap = new Capture(0);
camWorker = new Thread(() => {
while (true) {
Image<Bgr, byte> frame = cap.QueryFrame().ToImage<Bgr, byte>();
Image<Gray, byte> grayFrame = frame.Convert<Gray, byte>();
Rectangle[] faces = cascade.DetectMultiScale(grayFrame, 1.1, 10);
foreach (Rectangle face in faces) {
frame.Draw(face, new Bgr(Color.Red), 2);
}
imgCamUser.Image = frame;
Thread.Sleep(100);
}
});
camWorker.Start();
}
private void Application_ApplicationExit(object sender, EventArgs e) {
camWorker.Abort();
}
}
}
It works for a few frames, correctly draws a box around faces, and then just throws a:
An unhandled exception of type 'Emgu.CV.Util.CvException' occurred in System.Windows.Forms.dll
Additional information: OpenCV: index is out of range
And that's it. I'm using OpenCV 3.10, and Emgu for the .NET wrapper.
This exception is thrown in most cases when the Image object you are going to show in the ImageBox isn't containing any image. That means number of rows and columns are zero (dimention is 0x0 ). You can check that with debugger by adding a Breakpoint to the place imgCamUser.Image = frame; Here you can see whether that is the problem. If that is the problem (If image size is 0x0 ) most probably problem is with the way you use the Capture to assign an image to frame.
I have a problem with creating a Components Class in a Forms application in Visual Studio 2010 with C#. Where I create a target for a game where you are supposed to thow a ball att the target.
There are no errors in this but the application can not be run, there just pops up an window saying "Bounce stoped working", "Windows is trying to find the problem..". If I remove the code of course the app runs totally fine.
So somthing is wrong, but Im not really shore what part thats wrong. Anyone have an idea?
Just ignore my swedish comments..
In my Component Class Target.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace Bounce
{
class Target : Label
{
public double targetPosX, targetPosY;
public Target(Image image)
{
Image = image;
BackColor = Color.Transparent; // Sätter bakgrundsfärgen till genomskinlig på kontrollen
Size = new Size(205, 100); // Sätter storleken på kontrollen
Visible = true; // Ser till att bollarna syns
}
public void ShowTarget()
{
targetPosX = Location.X;
targetPosY = Location.Y;
}
}
}
The form bounce.cs in code (relevant part of the code):
//Target
Target target;
target = new Target(Image.FromFile("images/target.png"));
panel.Controls.Add(target);
target.Location = new Point(100, 200);
target.ShowTarget();
Problem is that your image path is invalid. It should be full path to image file. For example "c:\someDirectory\Images\target.png"
You set size to 205, 100 but Location to 100, 200
So Location is outside your rectangle...
I’m trying to fit a lot of rectangles into a Bitmap, which will be displayed in a picturebox. In my real code, I figure out the total width and height of a rectangle that can encompass all them, and then I divide that by the size of the Bitmap, to get my scaling factor. The problem is I can’t figure out how to perform the scaling. The code below is a simple version of what I need to do.
Please keep in mind that I cannot rely on the picturebox’s scaling abilities (stretch), and I don’t want to simply apply the scale to the width and height of all the rectangles, because in my real code it wouldn’t work very well. I need a way to shrink it down in Graphics. It is important the Bitmap stays the same size that it is (300 X 300). Thanks. The below code is what I've gotten so far, but nothing changes with the size.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication22
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Bitmap BM = new System.Drawing.Bitmap(300, 300);
Pen PenTest = new System.Drawing.Pen(Brushes.Red);
private void Form1_Load(object sender, EventArgs e)
{
using (Graphics GR = Graphics.FromImage(BM))
{
GR.DrawRectangle(PenTest, new Rectangle(0,0,500,500));
// I need a scale of 0.60 in this example, because 300/500 = .6
GR.ScaleTransform(.6F, .6F);//Doesn't Work. No Change at all in the size of the rectangle.
}
pictureBox1.Image = BM;
}
}
}
Graphics.ScaleTransform performs the transformation but it does not draw anything.
You would need to then draw a rectangle after performing the transform on the graphics object:
using (Graphics GR = Graphics.FromImage(BM))
{
// ....
GR.ScaleTransform(.6F, .6F);
GR.DrawRectangle(PenTest, new Rectangle(0,0,500,500));
}