I have extracted eyes and mouth from the face, but want to extract emotions from eyes and mouth.. However, mouth is not detected properly..
This is my code..
private void timer1_Tick(object sender, EventArgs e)
{
using (Image<Bgr, byte> nextFrame = cap.QueryFrame())
{
if (nextFrame != null)
{
// there's only one channel (greyscale), hence the zero index
//var faces = nextFrame.DetectHaarCascade(haar)[0];
Image<Gray, byte> grayframe = nextFrame.Convert<Gray, byte>();
Image<Gray, Byte> gray = nextFrame.Convert<Gray, Byte>();
Image<Gray, Byte> gray1 = nextFrame.Convert<Gray, Byte>();
var faces = grayframe.DetectHaarCascade(
haar, 1.4, 4,
HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(nextFrame.Width / 8, nextFrame.Height / 8)
)[0];
MCvAvgComp[][] eyes = gray.DetectHaarCascade(eye, 1.1, 1, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(20, 20));
gray.ROI = Rectangle.Empty;
MCvAvgComp[][] mouthsDetected = gray.DetectHaarCascade(mouth, 1.1, 10, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(20, 20));
gray1.ROI = Rectangle.Empty;
foreach (MCvAvgComp mouthsnap in mouthsDetected[0])
{
Rectangle mouthRect = mouthsnap.rect;
// mouthRect.Offset(f.rect.X, f.rect.Y);
nextFrame.Draw(mouthRect, new Bgr(Color.Red), 2);
detectedmouth = mouthRect;
}
foreach (MCvAvgComp eyesnap in eyes[0])
{
Rectangle eyeRect = eyesnap.rect;
// mouthRect.Offset(f.rect.X, f.rect.Y);
nextFrame.Draw(eyeRect, new Bgr(Color.Green), 2);
}
foreach (var face in faces)
{
nextFrame.Draw(face.rect, new Bgr(Color.LightGreen), 3);
facesnap = face.rect;
}
pictureBox1.Image = nextFrame.ToBitmap();
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
cap = new Capture(0);
// adjust path to find your xml
//haar = new HaarCascade("haarcascade_frontalface_alt2.xml");
haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
mouth = new HaarCascade("Mouth.xml");
eye = new HaarCascade("haarcascade_eye_tree_eyeglasses.xml");
}
private void button1_Click(object sender, EventArgs e)
{
Image snap = pictureBox1.Image;
snap.Save("c:\\snapshot.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
pictureBox2.Image = snap;
pictureBox3.Image = cropImage(snap,facesnap);
pictureBox4.Image = cropImage(snap, detectedmouth);
}
private static Image cropImage(Image img, Rectangle croparea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(croparea, bmpImage.PixelFormat);
return (Image)(bmpCrop);
}
Please help me in emotion detection and better mouth detection using c#.
I would try to look for a mouth in a face rectangle, instead of checking the hole picture.
var faces = grayframe.DetectHaarCascade(
haar, 1.4, 4,
HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(nextFrame.Width / 8, nextFrame.Height / 8)
)[0];
foreach (var f in faces)
{
//draw the face detected in the 0th (gray) channel with blue color
image.Draw(f.rect, new Bgr(Color.Blue), 2);
//Set the region of interest on the faces
gray.ROI = f.rect;
var mouthsDetected = gray.DetectHaarCascade(mouth,
1.1, 10,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(20, 20));
gray.ROI = Rectangle.Empty;
foreach (var m in mouthsDetected [0])
{
Rectangle mouthRect = m.rect;
mouthRect.Offset(f.rect.X, f.rect.Y);
image.Draw(mouthRect , new Bgr(Color.Red), 2);
}
}
i have divided face area in 2 rectangles top and bottom..and applied bottom rectangle to gray.ROI. and it works.. this is the code for both rectangles..
int halfheight = facesnap.Height/2;
int start = facesnap.X;
int start1 = facesnap.Y;
Rectangle top = new Rectangle(start,start1,facesnap.Width,halfheight);
int start2 = top.Bottom;
Rectangle bottom = new Rectangle(start, start2, facesnap.Width, halfheight);
nextFrame.Draw(bottom, new Bgr(Color.Yellow), 2);
//Set the region of interest on the faces
gray.ROI = bottom;
MCvAvgComp[][] mouthsDetected = gray.DetectHaarCascade(mouth,
1.1, 10,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(20, 20));
Related
i am using EmguCv in C# .net framework projec. i have used find contours and draw contours and after that the object is cropped and show in another picture box. the problem is i need the objects detected shape not rectangle shape image.
similar to this solution : How to crop the internal area of a contour?
but in emguCV C#.
here is what i have tried so far.
imgInput = new Image<Bgr, byte>(img_path);
if (imgInput == null)
{
return;
}
try
{
var temp = imgInput.Not().SmoothGaussian(5).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(250), new Gray(255));
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat m = new Mat();
CvInvoke.FindContours(temp, contours, m, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
int jk = 0;
dataGridView1.Columns.Add("stone_id", "Stone ID");
for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
if (jk == sel_row_id)
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 255, 17), 2);
if (contours.Size > 0)
{
Rectangle bbox = CvInvoke.BoundingRectangle(contours[0]); // here is the process of cropping rectangle.
imgInput.ROI = bbox;
var img = imgInput.Copy();
imgInput.ROI = Rectangle.Empty;
pictureBox5.Image = img.Bitmap;
}
}
else
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 0, 255), 2);
}
dataGridView1.Rows.Add(jk.ToString());
jk++;
//moments center of the shape
var moments = CvInvoke.Moments(contours[i]);
int x = (int)(moments.M10 / moments.M00);
int y = (int)(moments.M01 / moments.M00);
pictureBox4.Image = imgInput.Bitmap;
}
RefreshGridView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Here's what I do to Rotate and Scale. But so far, if the rotation is working, the scaling isn't and vice versa. So how do I combine rotation and scaling in one method? I feels like they can't coexist using my code.
....................................................................................................................................................................
Here's what I have for now:
Image Drawing:
public LayerClass ImageDrawing(LayerClass.Type img, Bitmap bm, Rectangle imgRect, String filepath, int angle, PaintEventArgs e)
{
bm = ImageClass.GrayscaleImage(bm);
bm = MakeTransparentImage(bm);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
bm = RotateImage(bm, angle, imgRect);
imgRect = new Rectangle((int)(Shape.center.X - (bm.Width / 2)), (int)(Shape.center.Y - (bm.Height / 2)), (int)bm.Width, (int)bm.Height);
e.Graphics.DrawImage(bm, imgRect);
this.imageBitmap = bm;
this.filePath = filePath;
this.rotationAngle = angle;
this.location = location;
this.imageRect = imgRect;
return new LayerClass(LayerClass.Type.Image, this, filePath, imgRect);
}
Rotation:
public static Bitmap RotateImage(Bitmap bitmap, float angle, Rectangle rect)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;
rect = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(resultBitmap))
{
Matrix matrix2 = new Matrix();
matrix2.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
g.Transform = matrix2;
g.DrawImage(bitmap, points);
return resultBitmap;
}
}
}
Scaling:
private void trackBar_ScaleImg_Scroll(object sender, EventArgs e)
{
if(rb_BothImage.Checked)
{
if (imgRect.Width > imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Height > imgRect.Width)
{
imgRect.Height = trackBar_ScaleImg.Value; //64mm
imgRect.Width = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Width == imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = trackBar_ScaleImg.Value;
}
imgRect.X = (int)(Shape.center.X - (imgRect.Width / 2));
imgRect.Y = (int)(Shape.center.Y - (imgRect.Height / 2));
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
pictureBox_Canvass.Invalidate();
}
You can add another matrix transformation for scaling: matrix.Scale(2, 2, MatrixOrder.Append);
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
matrix.Scale(2, 2, MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
hi,
I need to use color tracking.
The blob does not match my target object when I run my code in surface pro 4.
but the code is correct when I test it on my Acer.
anyone knows that why?
public void forobject(Bitmap image)//put setted color value into image1
{
BlobCounter blobCounter = new BlobCounter();
blobCounter.MinWidth = 5;
blobCounter.MinHeight = 5;
blobCounter.FilterBlobs = true;
blobCounter.ObjectsOrder = ObjectsOrder.Size;
//Grayscale griFiltre = new Grayscale(0.2125, 0.7154, 0.0721);
//Grayscale griFiltre = new Grayscale(0.2, 0.2, 0.2);
//Bitmap griImage = griFiltre.Apply(image);
BitmapData objectsData = image.LockBits(new Rectangle(0, 0, image.Width/2, image.Height/2), ImageLockMode.ReadOnly, image.PixelFormat);
// grayscaling
Grayscale grayscaleFilter = new Grayscale(0.2125, 0.7154, 0.0721);
UnmanagedImage grayImage = grayscaleFilter.Apply(new UnmanagedImage(objectsData));
// unlock image
image.UnlockBits(objectsData);
blobCounter.ProcessImage(image);
Rectangle[] rects = blobCounter.GetObjectsRectangles();
Blob[] blobs = blobCounter.GetObjectsInformation();
pictureBox_tracking.Image = image;//????
if (rdiobtn_singletracking.Checked)
{
// Single Tracking--------
foreach (Rectangle recs in rects)
{
if (rects.Length > 0)
{
Rectangle objectRect = rects[0];
//Graphics g = Graphics.FromImage(image);
Graphics g = pictureBox_real.CreateGraphics();
using (Pen pen = new Pen(Color.FromArgb(252, 3, 26), 2))
{
g.DrawRectangle(pen, objectRect);
}
//Drawn by the rectangle coordinates is taken away.
//int objectX = objectRect.X; //+ (objectRect.Width / 2);
//int objectY = objectRect.Y; //+ (objectRect.Height / 2);
x = objectRect.X;
y = objectRect.Y;
w = objectRect.Width;
h = objectRect.Height;
// g.DrawString(objectX.ToString() + "X" + objectY.ToString(), new Font("Arial", 12), Brushes.Red, new System.Drawing.Point(250, 1));
g.Dispose();
}
I have developed a working C# face recognition program using EmguCV.
However, if I load "haarcascade_fullbody.xml" instead of "haarcascade_frontalface_alt_tree.xml" I get the almighty Access Violation.
This is the code;
public Bitmap detection(Bitmap Source)
{
List<Image<Gray, byte>> TrainedImages = this.TrainedImages;
List<String> Names = this.Names;
Image<Bgr, byte> ImageFrame = new Image<Bgr, byte>(Source);
Image<Gray, byte> grayFrame = ImageFrame.Convert<Gray, byte>();
Image<Bgr, byte> overlay = new Image<Bgr, byte>(Source.Width, Source.Height);
Graphics FaceCanvas;
List<String> finimg = new List<String>();
//HaarCascade haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
HaarCascade haar = new HaarCascade("haarcascade_fullbody.xml");
var faces = grayFrame.DetectHaarCascade(haar, 1.1, 3, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new System.Drawing.Size(25, 25))[0];
foreach (var face in faces)
{
overlay.Draw(face.rect, new Bgr(System.Drawing.Color.Green), 3);
tempbmp = new Bitmap(100, 100);
FaceCanvas = Graphics.FromImage(tempbmp);
FaceCanvas.DrawImage(grayFrame.ToBitmap(), 0, 0, face.rect, GraphicsUnit.Pixel);
detected.Add(tempbmp);
if (doit)
{
saveBitmap(tempbmp, trainpath, trainnamer.Text);
doit = false;
}
if (doit10)
{
for (int k = 1; k <= 10; k++)
saveBitmap(tempbmp, trainpath, trainnamer.Text);
doit10 = false;
}
try
{
MCvTermCriteria termCrit = new MCvTermCriteria(TrainedImages.ToArray().Length, 0.001);//????????????
EigenObjectRecognizer recognizer = new EigenObjectRecognizer(TrainedImages.ToArray(), Names.ToArray(), 2500, ref termCrit);
MCvFont font = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 0.5d, 0.5d);
String name = recognizer.Recognize(new Image<Gray, byte>(tempbmp));
if (Names.Contains(name) == false)
name = "Stranger";
else
name = removeformat(name);
overlay.Draw(name, ref font, new System.Drawing.Point(face.rect.Left, face.rect.Top - 5), new Bgr(System.Drawing.Color.Green));
finimg.Add(name);
}
catch (IndexOutOfRangeException)
{
MCvFont font = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 0.5d, 0.5d);
ImageFrame.Draw("Stranger", ref font, new System.Drawing.Point(face.rect.Left, face.rect.Top - 5), new Bgr(color));
continue;
}
}
detected.Clear();
Bitmap supra = overlay.ToBitmap();
supra.MakeTransparent(System.Drawing.Color.Black);
return supra;
}
Apparently there is a problem with the xml, as any other haarcascade I try to load loads succesfully. I recommend using the HOGDescriptor instead or "haarcascade_mcs_upperbody.xml" for pedestrian detecting.
I am working with emguCV for finding contours essential points then saving this point in a file and user redraw this shape in future. so, my goal is this image:
example
my solution is this:
1. import image to picturebox
2. edge detection with canny algorithm
3. finding contours and save points
I found a lot of points with below codes but i can't drawing first shape with this point!
using Emgu.CV;
using Emgu.Util;
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.Image);
Image<Bgr, Byte> img = new Image<Bgr, byte>(bmp);
Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp();
Gray cannyThreshold = new Gray(80);
Gray cannyThresholdLinking = new Gray(120);
Gray circleAccumulatorThreshold = new Gray(120);
Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking).Not();
Bitmap color;
Bitmap bgray;
IdentifyContours(cannyEdges.Bitmap, 50, true, out bgray, out color);
pictureBox1.Image = color;
}
public void IdentifyContours(Bitmap colorImage, int thresholdValue, bool invert, out Bitmap processedGray, out Bitmap processedColor)
{
Image<Gray, byte> grayImage = new Image<Gray, byte>(colorImage);
Image<Bgr, byte> color = new Image<Bgr, byte>(colorImage);
grayImage = grayImage.ThresholdBinary(new Gray(thresholdValue), new Gray(255));
if (invert)
{
grayImage._Not();
}
using (MemStorage storage = new MemStorage())
{
for (Contour<Point> contours = grayImage.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST, storage); contours != null; contours = contours.HNext)
{
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.015, storage);
if (currentContour.BoundingRectangle.Width > 20)
{
CvInvoke.cvDrawContours(color, contours, new MCvScalar(255), new MCvScalar(255), -1, 1, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, new Point(0, 0));
color.Draw(currentContour.BoundingRectangle, new Bgr(0, 255, 0), 1);
}
Point[] pts = currentContour.ToArray();
foreach (Point p in pts)
{
//add points to listbox
listBox1.Items.Add(p);
}
}
}
processedColor = color.ToBitmap();
processedGray = grayImage.ToBitmap();
}
In your code you have added contour approximation operation
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.015, storage);
This contour approximation will approximate your Contour to a nearest polygon & so your actual points got shifted. If you want to reproduce the same image you need not to do any approximation.
Refer this thread.