Opencv Emgu c# face extraction - c#

So far I have managed to make my programme to work and detect face and now what i want to do is that extract the area detected and display in new picture box that i have added also after this is done i want to add pics to database and compare detected faces with them.
So please help
private void ProcessFrame(object sender, EventArgs arg)
{
Image<Bgr, Byte> frame = _capture.QueryFrame();
Image<Gray, Byte> gray = frame.Convert<Gray, Byte>(); //Convert it to Grayscale
//normalizes brightness and increases contrast of the image
gray._EqualizeHist();
//Read the HaarCascade objects
HaarCascade face = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
HaarCascade eye = new HaarCascade("haarcascade_eye.xml");
//Detect the faces from the gray scale image and store the locations as rectangle
//The first dimensional is the channel
//The second dimension is the index of the rectangle in the specific channel
MCvAvgComp[][] facesDetected = gray.DetectHaarCascade(
face,
1.1,
10,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_ROUGH_SEARCH,
new Size(20, 20));
foreach (MCvAvgComp f in facesDetected[0])
{
//draw the face detected in the 0th (gray) channel with blue color
frame.Draw(f.rect, new Bgr(Color.Blue), 2);
/*
//Set the region of interest on the faces
gray.ROI = f.rect;
MCvAvgComp[][] eyesDetected = gray.DetectHaarCascade(
eye,
1.1,
10,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_ROUGH_SEARCH,
new Size(20, 20));
gray.ROI = Rectangle.Empty;
foreach (MCvAvgComp e in eyesDetected[0])
{
Rectangle eyeRect = e.rect;
eyeRect.Offset(f.rect.X, f.rect.Y);
frame.Draw(eyeRect, new Bgr(Color.Red), 2);
}*/
}
pictureBox1.Image = frame.ToBitmap();Application.DoEvents();
}
private void button1_Click(object sender, EventArgs e)
{
#region if capture is not created, create it now
if (_capture == null)
{
try
{
_capture = new Capture();
}
catch (NullReferenceException excpt)
{
MessageBox.Show(excpt.Message);
}
}
#endregion
if (_capture != null)
{
if (_captureInProgress)
{ //stop the capture
button1.Text = "Start Capture";
Application.Idle -= ProcessFrame;
}
else
{
//start the capture
button1.Text = "Stop";
Application.Idle += ProcessFrame;
}
_captureInProgress = !_captureInProgress;
}
}

I have managed to do that but i am placing this answer to help others if they are in same trouble
gray.ROI = f.rect;
and then you can assign gray to any picture box this will show only detected area

Related

improve image quality of cropped image c#

i created a windows form c# application. It has feature to crop image. After cropping image. it show preview in other picturebox. My problem is the cropping place little bit blur in picture box. .Here is picture to understand what i meant...I want to fix it
enter image description here
here is the code i used.
{
string root = #"C:\FuelPass";
// If directory does not exist, create it.
if (!System.IO.Directory.Exists(root))
{
System.IO.Directory.CreateDirectory(root);
}
Bitmap bmp = new Bitmap(previewimg.Width, previewimg.Height);
previewimg.DrawToBitmap(bmp, new Rectangle(0, 0, previewimg.Width, previewimg.Height));
pictureBox2.DrawToBitmap(bmp, new Rectangle(pictureBox2.Location.X - previewimg.Location.X, pictureBox2.Location.Y - previewimg.Location.Y, pictureBox2.Width, pictureBox2.Height));
String savename="";
// DateTime dt = new DateTime();
// bmp.Save(#"C:\Fuelpass\" +dt.ToString()+ " .jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
bmp.Save(#"C:\Fuelpass\output-" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
Form2 f2 = new Form2();
f2.Show();
// MessageBox.Show("Image has been saved");
// SaveFileDialog dialog = new SaveFileDialog();
// dialog.Filter = "JPG(*.JPG)|*.jpg";
// if (dialog.ShowDialog() == DialogResult.OK)
// {
// previewimg.Image.Save(dialog.FileName);
// pictureBox2.Image.Save(dialog.FileName);
// }
// }
}
private void PictureBoxLoad_MouseUp_1(object sender, MouseEventArgs e)
{
//pictureBox1.Image.Clone();
try
{
if (IsMouseDown == true)
{
LocationX1Y1 = e.Location;
IsMouseDown = false;
if (Rect != null)
{
Bitmap bit = new Bitmap(PictureBoxLoad.Image, PictureBoxLoad.Width, PictureBoxLoad.Height);
Bitmap cropImg = new Bitmap(Rect.Width, Rect.Height);
Graphics g = Graphics.FromImage(cropImg);
g.DrawImage(bit, 0, 0, Rect, GraphicsUnit.Pixel);
pictureBox2.Image = cropImg;
}
}
}
catch { }
}
private Rectangle GetRect()
{
Rect = new Rectangle();
Rect.X = Math.Min(LocationXY.X, LocationX1Y1.X);
Rect.Y = Math.Min(LocationXY.Y, LocationX1Y1.Y);
Rect.Width = Math.Abs(LocationXY.X - LocationX1Y1.X);
Rect.Height = Math.Abs(LocationXY.Y - LocationX1Y1.Y);
return Rect;
}

enlarge / shrink PictureBox but maintain pixel ratio c#

I could not find a better title.
So this is what I want to do:
I have a picturebox that is 28x28 pixels
I am working on a AI project and my idea is to make an OCR for numbers,
I found training data but all the images are 28x28 pixels,
so my ideea is to make a picturebox that size,
draw on it and feed that info to the neural network.
My problem is graphicly for the moment:
How do I make a 28x28 picturebox and somehow enlarge it but maintain the pixel count.
I put the picturebox into a panel and I want the picturebox to fill the panel.
My idea would be to somehow scale it up and after drawing on it scale it back down, but how can I accomplish this?
mathematically how can this be done?
And what would be the best way to draw on that picturebox (line, fillelipse , etc) so the data could be feed into the NN (after normalizing it ofc).
I figured out a solution , maybe it will help someone in the future:
List<KeyValuePair<int, int>> coordonateList = new List<KeyValuePair<int, int>>();
// drawPictureBox size is 280 x 280 (28 * 10, 28 * 10)
private void pbImage_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
}
private void drawPictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
Point point = drawPictureBox.PointToClient(Cursor.Position);
DrawPoint((point.X), (point.Y));
}
}
private void drawPictureBox_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
public void DrawPoint(int x, int y)
{
using (Graphics g = Graphics.FromImage(bitmap))
{
SolidBrush brush = new SolidBrush(Color.White);
g.FillRectangle(brush, x, y, 10, 10);
coordonateList.Add(new KeyValuePair<int,int>(x/10,y/10));
}
drawPictureBox.Image = bitmap;
}
private void zoomImage(Bitmap bitmap)
{
var result = new Bitmap(28,28);
using (Graphics g1 = Graphics.FromImage(result))
{
SolidBrush brush = new SolidBrush(Color.White);
foreach (var item in coordonateList)
{
g1.FillRectangle(brush, item.Key, item.Value, 1, 1);
}
pictureBox1.Image = result;
}

c# Drawing with gdi32.dll vs System.Drawing.Graphics

So I have some code that creates a highlight effect on top of a picture box with gdi32.dll and I am wondering if there is a simpler way to do it with System.Drawing.Graphics? Basically with the gdi32.dll, I have to capture a screen shot after drawing, post that to my picturebox and then I am able to draw more stuff and change the color of the pen that I use. If I just try to change the pen thickness and color and draw on the screen again, if changes what I already drew.
Now I have a version of this that uses System.Drawing.Graphics and lots of math with FillPolygon but if I draw over an area I already drew on, it just makes the area I drew on darker. It does not do this with gdi32.dll which justr shades as long as you have not already shaded the area with the mouse. Any suggestions?
public partial class Form9 : Form
{
private bool is_mouse_down { get; set; } // Will check if the mouse is down or not.
private Color Pen_Color = new Color();
private int Pen_Type { get; set; }
private int Thickness { get; set; }
private bool Start { get; set; }
List<Point> Points = new List<Point>();
public Form9()
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
Pen_Color = Color.Blue;
Pen_Type = 13; // Type = 9 for highlighter, Type = 13 for solid.
Thickness = 2;
Start = false;
pictureBox1.MouseDown += pictureBox1_MouseDown;
pictureBox1.MouseUp += pictureBox1_MouseUp;
pictureBox1.MouseMove += pictureBox1_MouseMove;
pictureBox1.Paint += pictureBox1_OnPaint;
}
private void DrawHighlight(Graphics g, Point[] usePoints, int brushSize, int penType, Color brushColor)
{
int useColor = System.Drawing.ColorTranslator.ToWin32(brushColor);
IntPtr pen = GetImage.GDI32.CreatePen(GetImage.GDI32.PS_SOLID, brushSize, (uint)useColor);
IntPtr hDC = g.GetHdc();
IntPtr xDC = GetImage.GDI32.SelectObject(hDC, pen);
GetImage.GDI32.SetROP2(hDC, penType);//GetImage.GDI32.R2_MASKPEN);
for (int i = 1; i <= usePoints.Length - 1; i++)
{
Point p1 = usePoints[i - 1];
Point p2 = usePoints[i];
GetImage.GDI32.MoveToEx(hDC, p1.X, p1.Y, IntPtr.Zero);
GetImage.GDI32.LineTo(hDC, p2.X, p2.Y);
}
GetImage.GDI32.SetROP2(hDC, GetImage.GDI32.R2_COPYPEN);
GetImage.GDI32.SelectObject(hDC, xDC);
GetImage.GDI32.DeleteObject(pen);
g.ReleaseHdc(hDC);
}
private void pictureBox1_OnPaint(object sender, PaintEventArgs e)
{
if (Start)
{
base.OnPaint(e);
if (is_mouse_down)
{
DrawHighlight(e.Graphics, Points.ToArray(), Thickness, Pen_Type, Pen_Color);
}
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Points.Clear();
Start = true;
is_mouse_down = true;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
is_mouse_down = false;
using (Image img = CaptureScreen())
{
try
{
if (System.IO.File.Exists(Program.ProgramPath + #"\Temp\marked.bmp"))
{
System.IO.File.Delete(Program.ProgramPath + #"\Temp\marked.bmp");
}
}
catch (Exception Ex)
{
MessageBox.Show("File Delete Error" + Environment.NewLine + Convert.ToString(Ex));
}
try
{
img.Save(Program.ProgramPath + #"\Temp\marked.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
catch (Exception Ex)
{
MessageBox.Show("Unable to save Screenshot" + Environment.NewLine + Convert.ToString(Ex));
}
}
if (System.IO.File.Exists(Program.ProgramPath + #"\Temp\marked.bmp"))
{
using (FileStream fs = new System.IO.FileStream(Program.ProgramPath + #"\Temp\marked.bmp", System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.Read))
{
pictureBox1.Image = Image.FromStream(fs);
}
}
pictureBox1.Invalidate(); // Refreshes picturebox image.
}
public Image CaptureScreen()
{
GetImage gi = new GetImage();
return gi.CaptureWindow(GetImage.User32.GetDesktopWindow());
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (is_mouse_down == true) // Check to see if the mouse button is down while moving over the form.
{
Points.Add(new Point(e.X, e.Y));
pictureBox1.Invalidate(); // Refreshes picturebox image.
}
}
Here are a couple photos of what I am talking about:
Using System.Drawing.Graphics:
Using gdi32.dll:
UPDATE
After testing some of your code...I got a some strange stuff.
This is a way to draw multiple independent stroke of semi-transparent color without piling up the alpha:
It uses tow lists, one for the strokes and one for the current stroke:
List<List<Point>> strokes = new List<List<Point>>();
List<Point> currentStroke = new List<Point>();
They are filled in the usual way
private void canvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
currentStroke.Add(e.Location);
if (currentStroke.Count == 1)
currentStroke.Add(new Point(currentStroke[0].X + 1,
currentStroke[0].Y));
canvasInvalidate();
}
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
currentStroke.Add(e.Location);
canvas.Invalidate();
}
}
private void canvas_MouseUp(object sender, MouseEventArgs e)
{
if (currentStroke.Count > 1)
{
strokes.Add(currentStroke.ToList());
currentStroke.Clear();
}
canvas.Invalidate();
}
In this version we avoid overlay effects of overlapping strokes by drawing all pixels in only one call. All the pixels are painted by creating a GraphicsPath from the strokes and and filling it:
private void canvas_Paint(object sender, PaintEventArgs e)
{
if (strokes.Count > 0 || currentStroke.Count > 0)
{
GraphicsPath gp = new GraphicsPath();
gp.FillMode = FillMode.Winding;
if (currentStroke.Count > 0)
{
gp.AddCurve(currentStroke.ToArray());
gp.CloseFigure();
}
foreach (var stroke in strokes)
{
gp.AddCurve(stroke.ToArray());
gp.CloseFigure();
}
using (SolidBrush b = new SolidBrush(Color.FromArgb(77, 177, 99, 22)))
{
e.Graphics.FillPath(b, gp);
}
}
}
Note that you should take care not to move back onto the current stroke while drawing it or else the croosing path parts will create holes!
A Clear or Save Button are simple, the former Clears the two list and invalidates, the latter would use DrawToBitmap to save the control..
Note: To avoid flicker do make sure the canval Panel is DoubleBuffered!
Update:
Here is another way that uses a Pen to draw the overlay. To avoid the piling up of alpha and changed color values (depending on the PixelFormat) it uses a fast function to modify all set pixels in the overlay to have the same overlay color:
The stroke collection code is the same. The Paint is reduced to calling a function to create an overlay bitmap and drawing it:
private void canvas_Paint(object sender, PaintEventArgs e)
{
using (Bitmap bmp = new Bitmap(canvas.ClientSize.Width,
canvas.ClientSize.Height, PixelFormat.Format32bppPArgb))
{
PaintToBitmap(bmp);
e.Graphics.DrawImage(bmp, 0, 0);
}
The first function does the drawing, pretty much like before, but with simple pen strokes:
private void PaintToBitmap(Bitmap bmp)
{
Color overlayColor = Color.FromArgb(77, 22, 99, 99);
using (Graphics g = Graphics.FromImage(bmp))
using (Pen p = new Pen(overlayColor, 15f))
{
p.MiterLimit = p.Width / 2;
p.EndCap = LineCap.Round;
p.StartCap = LineCap.Round;
p.LineJoin = LineJoin.Round;
g.SmoothingMode = SmoothingMode.AntiAlias;
if (currentStroke.Count > 0)
{
g.DrawCurve(p, currentStroke.ToArray());
}
foreach (var stroke in strokes)
g.DrawCurve(p, stroke.ToArray());
}
SetAlphaOverlay(bmp, overlayColor);
}
It also calls the function that 'flattens' all set pixels to the overlay color:
void SetAlphaOverlay(Bitmap bmp, Color col)
{
Size s = bmp.Size;
PixelFormat fmt = bmp.PixelFormat;
Rectangle rect = new Rectangle(Point.Empty, s);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
int size1 = bmpData.Stride * bmpData.Height;
byte[] data = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1);
for (int y = 0; y < s.Height; y++)
{
for (int x = 0; x < s.Width; x++)
{
int index = y * bmpData.Stride + x * 4;
if (data[index + 0] + data[index + 1] + data[index + 2] > 0)
{
data[index + 0] = col.B;
data[index + 1] = col.G;
data[index + 2] = col.R;
data[index + 3] = col.A;
}
}
}
System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
}
It uses LockBits, so it is pretty fast..
Here it is in action:
Update 2:
Just for the fun of it here is an extension of only a few lines that adds the option of drawing filled curves:
The fill mode is stored in a cheapo hack by having the 1st element twice. These are the changes:
In the MouseDown:
currentStroke.Add(e.Location);
if (cbx_Fill.Checked)
currentStroke.Add(e.Location);
And in the PaintToBitmap:
g.SmoothingMode = SmoothingMode.AntiAlias;
if (currentStroke.Count > 0)
{
if (cbx_Fill.Checked)
g.FillClosedCurve(b, currentStroke.ToArray());
else
g.DrawCurve(p, currentStroke.ToArray());
}
foreach (var stroke in strokes)
if (stroke[0]==stroke[1])
g.FillClosedCurve(b, stroke.ToArray());
else
g.DrawCurve(p, stroke.ToArray());
And one more demo:

How load image with backgroundworker and display to picturebox?

I have to display images in a picturebox. The images are high resolution scans of archives. Because of this high resolution my panning en zoom features are very slow. To solve this problem I reduced the bitmap width and length while maintaining the images readable. In my code in drawOriginalImage(); the variable "quality" is thus the factor which I reduce the size of the bitmap. This is how I did it:
private void drawOriginalImage(int quality) {
try {
int x = originalImage.Width / quality,
y = originalImage.Height / quality;
pictureBox.Image = (Image)new Bitmap(originalImage, x, y);
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
}
catch (Exception ex) {
throw ex;
}
}
But this solution brings another problem. This step can be very long:
pictureBox.Image = (Image)new Bitmap(originalImage, x, y);
Because of this slowness, I wanted to process this step with the Backgroundworker feature. Now my code looks like this:
private void drawOriginalImage(int quality) {
Cursor = Cursors.AppStarting;
backgroundWorker.RunWorkerAsync(new Point(
originalImage.Width / quality,
originalImage.Height / quality
));
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
Point p = (Point)e.Argument;
e.Result = new Bitmap(originalImage, p.X, p.Y);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
MessageBox.Show("Image too big.\nOriginal error:\n" + e.Error);
}
else {
pictureBox.Image = (Image)e.Result;
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
Cursor = Cursors.Default;
}
}
But it doesn't work. I see the cursor changing from "Cursors.AppStarting" to "Cursors.Default" and thus the task is probably completed. But there is no image in my picturebox? How can that be? What am I doing wrong?
When I debug it, the program never goes in "backgroundWorker_RunWorkerCompleted". How can it be?
I have found it. I had hook up all my events correctly by adding this:
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);

C# rectangle drawing and screenshot

So, let me just start out by showing you the code I have now:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
currentPos = startPos = e.Location;
drawing = true;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
currentPos = e.Location;
//Calculate X Coordinates
if (e.X < startPos.X)
{
CurrentTopLeft.X = e.X;
}
else
{
CurrentTopLeft.X = startPos.X;
}
//Calculate Y Coordinates
if (e.Y < startPos.Y)
{
CurrentTopLeft.Y = e.Y;
}
else
{
CurrentTopLeft.Y = startPos.Y;
}
if (drawing)
this.Invalidate();
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (drawing)
{
this.Hide();
SaveScreen();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Color col = Color.FromArgb(75, 100, 100, 100);
SolidBrush b = new SolidBrush(col);
if (drawing)
e.Graphics.FillRectangle(b, getRectangle());
}
My SaveScreen function:
private void SaveScreen()
{
ScreenShot.CaptureImage(CurrentTopLeft, Point.Empty, getRectangle());
}
The CaptureImage function:
public static void CaptureImage(Point SourcePoint, Point DestinationPoint, Rectangle SelectionRectangle)
{
string FilePath = "temp.jpg";
using (Bitmap bitmap = new Bitmap(SelectionRectangle.Width, SelectionRectangle.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(SourcePoint, DestinationPoint, SelectionRectangle.Size);
}
bitmap.Save(FilePath, ImageFormat.Jpeg);
}
string Filename = String.Format("{0:yyyy-M-d-HH-mm-ss}", DateTime.Now) + ".jpg";
string Server = "";
System.Net.WebClient Client = new System.Net.WebClient();
Client.Headers.Add("Content-Type", "image/jpeg");
byte[] result = Client.UploadFile(Server + "upload.php?filename=" + Filename + "", "POST", FilePath);
string s = System.Text.Encoding.UTF8.GetString(result, 0, result.Length);
Program.mainForm.Notify(Server + Filename);
File.Delete(FilePath);
}
This is just the basic code I have for drawing a rectangle on the screen. When the rectangle is drawn, it takes an image, works perfectly.
The problem is, that the drawing of the rectangle is not smooth at all. I have enabled doublebuffering and pretty much tried everything, but with no luck.
Also, I would like to grab the current screen, or freeze it, and then be able to draw on that frozen screen, instead of just drawing on top of the active screen if you understand me. How would this be done?
Any help is much appreciated!
Maybe that post will help you:
How to draw directly on the Windows desktop, C#?
You could try something like this:
int width =
Screen.PrimaryScreen.Bounds.Width,
height = Screen.PrimaryScreen.Bounds.Height;
Bitmap screen = default( Bitmap );
try
{
screen = new Bitmap
(
width,
height,
Screen.PrimaryScreen.BitsPerPixel == 32 ?
PixelFormat.Format32bppRgb :
PixelFormat.Format16bppRgb565
);
using (Graphics graphics = Graphics.FromImage(screen))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.CopyFromScreen
(
new Point() { X = 0, Y = 0 },
new Point() { X = 0, Y = 0 },
new Size() { Width = width, Height = height },
CopyPixelOperation.SourceCopy
);
// Draw over the "capture" with Graphics object
}
}
finally
{
if (screen != null)
{
screen.Dispose();
}
}

Categories