I am new to Emgucv and I am working on face movement direction detection
I had come across many codes in Internet but they are very difficult to understand.
So can you please provide a easy and understandable code or links for learning this situation.
Thanks in advance
Based on this :
Bitmap bmp = new Bitmap(); // your bitmap contain a face
Mat mat = GetMatFromSDImage(bmp);
using (var nextFrame = mat.ToImage<Bgr, Byte>())
{
if (nextFrame != null)
{
Image<Gray, byte> grayframe = nextFrame.Convert<Gray, byte>();
Rectangle[] faces = mHaarCascade.DetectMultiScale(grayframe, 1.1, 10, Size.Empty);
if (faces.Count() > 0)
{
// some faces are detected
// you can check the X and Y of faces here
}
}
}
private Mat GetMatFromSDImage(Bitmap image)
{
int stride = 0;
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, image.Width, image.Height);
System.Drawing.Imaging.BitmapData bmpData = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, image.PixelFormat);
System.Drawing.Imaging.PixelFormat pf = image.PixelFormat;
if (pf == System.Drawing.Imaging.PixelFormat.Format32bppArgb)
{
stride = image.Width * 4;
}
else
{
stride = image.Width * 3;
}
Image<Bgra, byte> cvImage = new Image<Bgra, byte>(image.Width, image.Height, stride, (IntPtr)bmpData.Scan0);
image.UnlockBits(bmpData);
return cvImage.Mat;
}
so faces contains the array of Rectangle bounding faces. you can check the X and Y property of the rectangles to check if it moves and compares it with the initial position to detect it's direction.
Update based on comment
To detect head rotation a simple solution can be eye detection. you can use haarcascade_eye.xml to detect ayes. then you can calculate the rotation form each eye's X and Y position.
Here you can find a simple example of eye detection
Related
Using a sliced strock as a timer
I already have the use of a running sliced strock like a timer. I wanted to do the same with a picture with rounded corners, but it didn't work and it was cropped for a round one.
Real and
Cropped after slice
This is the code I used:
for (int i = 0; i <= 100; i++)
{
Bitmap bitmap2 = Pie(bitmap, i);
var ms = new MemoryStream();
bitmap2.Save(ms, ImageFormat.Png);
RendererManager.LoadImage("NewVisuals.roundedRect" + i, ms);
}
public static Bitmap Pie(System.Drawing.Image source, int pct)
{
Bitmap bitmap = new Bitmap(source.Width, source.Height);
using GraphicsPath graphicsPath = new GraphicsPath();
graphicsPath.AddArc(0, 0, source.Width, source.Height, -90f, 3.6f * (float)pct);
using Graphics graphics = Graphics.FromImage(bitmap);
graphics.SetClip(graphicsPath);
graphics.DrawImage(source, 0, 0, source.Width, source.Height);
return bitmap;
}
How can I avoid cutting corners, but just slice the picture as shown in the example?
Example what i need
Find out how you can slice the outline for later use
I want to rotate a Bitmap around a given point and have that point become the new center of the Bitmap.
Here is what I tried first
Bitmap rotate(Bitmap img, float angle, int cx, int cy)
{
Bitmap result = new Bitmap(img.Width, img.Height);
int middleX = img.Width / 2,
middleY = img.Height / 2;
using (Graphics g = Graphics.FromImage(result))
{
g.Clear(Color.Black);
g.TranslateTransform(cx, cy);
g.RotateTransform(angle);
g.TranslateTransform(-cx, -cy);
g.TranslateTransform(middleX - cx, middleY - cy); //shift (cx, cy) to be at the center, does not work
g.DrawImage(originalImage, new Point(0, 0));
}
return result;
}
But when I go to translate the image after rotation, the translation is in the original space instead of this new rotated space and doesn't come out right.
I tried basically every combination of things I could think of with no luck. Search results only describe how to rotate around a point.
Original image (red dot is the point to rotate around) -
After rotating by 45 degrees the image should be translated so that the red dot is the center of the image
You have to set the matrix order to Append for the final translation. I have no idea why this is what makes it work. I literally just brute force tried every possible way of doing everything until it worked. I'd still be interested in an explanation of what is going on though.
Bitmap rotate(Bitmap img, float angle, int cx, int cy)
{
Bitmap result = new Bitmap(img.Width, img.Height);
int mx = img.Width / 2,
my = img.Height / 2;
using (Graphics g = Graphics.FromImage(result))
{
g.Clear(Color.Black);
g.TranslateTransform(cx, cy);
g.RotateTransform(angle);
g.TranslateTransform(-cx, -cy);
g.TranslateTransform(mx - cx, my - cy, MatrixOrder.Append);
g.DrawImage(originalImage, new Point(0, 0));
}
return result;
}
I use:
Emgucv 4.0.1
Opencv 4.1.0
I have a series of circles detected with HoughCircles function that I need to analize one by one.
I need to calculate how much color is in the rounded green circle, so I have to extract only the circle image but I know how to extract only the box that contains much more pixel than the circle. How to extract only the image inside the surrounded green area?
See images in link below.
1) Source Image
2) Boxed image I retrieved with more pixel than i want
3) Image that I would like to extract
// m_ListCircles = list from HoughCircles() circles coordinates.
// cell = cell number to extract.
// pictureBox1 = main picturebox with all circles detected.
// pictureBoxROI = picturebox destination single circles cutted.
int id = (int)m_ListCircles[0 + cell ];
int x = (int)m_ListCircles[1 + cell ];
int y = (int)m_ListCircles[2 + cell ];
int r = (int)m_ListCircles[3 + cell ]; // radius
// box area around the circle
int X0 = x;
int Y0 = y;
int X1 = x + r * 2;
int Y1 = y + r * 2;
// area to copy
int wid = Math.Abs(X0 - X1);
int hgt = Math.Abs(Y0 - Y1);
if ((wid < 1) || (hgt < 1)) return;
// create a rectangle are to copy
Rectangle source_rectangle = new Rectangle(Math.Min(X0, X1),Math.Min(Y0,Y1), wid, hgt);
// assign the area copied to image var
var image = new Image<Bgr, byte>(new Bitmap(pictureBox1.Image));
image.ROI = source_rectangle;
// show image
pictureBoxROI.Image = image.Bitmap;
pictureBoxROI.Refresh();
/*
// tried this but result is always a black image.
Point xyCell = new Point();
xyCell.X = X0;
xyCell.Y = Y0;
Image<Gray, byte> mask = new Image<Gray, byte>(image.Width, image.Height);
CvInvoke.Circle(mask, xyCella, r, new MCvScalar(255, 255, 255), -1,
LineType.AntiAlias, 0);
Image<Bgr, byte> dest = new Image<Bgr, byte>(image.Width, image.Height);
dest = image.And(image, mask);
pictureBoxROI.Image = dest.Bitmap;
pictureBoxROI.Refresh();
*/
You can always create masks of ROI form the found circles and analyze tha images like that
Custom ROI - this shows how to use the mask
You can only have rectangular images. However you can after cutting the rectangle set all the pixels outside of the circle to transparent.
You can determine which pixels are outside of the circle by calculating their distance from the center point of your image using pythagoras.
This is very slow of course, as you must loop over all pixels, but for low pixel counts it's reasonably fast.
try
{
Image rectCroppedImage = originalImage.Clone(CropRect, originalImage.PixelFormat);
double r = rectCroppedImage.Height; // because you are centered on your circle
Bitmap img = new Bitmap(rectCroppedImage);
for (int x = 0; x < img.Width; x++)
{
for (int y = 0; y < img.Height; y++)
{
// offset to center
int virtX = x - img.Width / 2;
int virtY = y - img.Height / 2;
if (Math.Sqrt(virtX * virtX + virtY * virtY) > r)
{
img.SetPixel(x, y, Color.Transparent);
}
}
}
return img; // your circle cropped image
}
catch (Exception ex)
{
}
This could also be achieved by using a mask and "multiplying" your image with a white circle. Such a thing can be achieved for example with image magick. You can find an ImageMagick NuGet packet here: https://github.com/dlemstra/Magick.NET
I'm trying to rotate photo with SkiaSharp to 90 degrees with following code:
public SKBitmap Rotate()
{
var bitmap = SKBitmap.Decode("test.jpg");
using (var surface = new SKCanvas(bitmap))
{
surface.RotateDegrees(90, bitmap.Width / 2, bitmap.Height / 2);
surface.DrawBitmap(bitmap.Copy(), 0, 0);
}
return bitmap;
}
But when I save bitmap to JPEG file, it has margins both on top and bottom of image.
Original image: http://imgur.com/pGAuko8.
Rotated image: http://imgur.com/bYxpmI7.
What am I doing wrong?
You may want to do something like this:
public static SKBitmap Rotate()
{
using (var bitmap = SKBitmap.Decode("test.jpg"))
{
var rotated = new SKBitmap(bitmap.Height, bitmap.Width);
using (var surface = new SKCanvas(rotated))
{
surface.Translate(rotated.Width, 0);
surface.RotateDegrees(90);
surface.DrawBitmap(bitmap, 0, 0);
}
return rotated;
}
}
The reason for this (or yours not working as expected) is that you are rotating the bitmap on itself. You have basically taken an image, and then made a copy on draw it onto the first image. Thus, you still have the margins from the image below.
What I did was to create a NEW bitmap and then draw the decoded bitmap onto that.
The second "issue" is that you are rotating the image, but you are not changing the canvas dimensions. If the bitmap is 50x100, and then you rotate 90 degrees, the bitmap is now 100x50. As you can't actually change the dimensions of a bitmap once created, you have to create a new one. You can see this in the output image as it is actually cropped off a bit.
Hope this helps.
Matthew's solution works for me too, but i had an issue when i tried to rotate bitmaps more than 90° or -90° (bitmap was drawed "out of display"). I highly recommend using this solution. Slightly modified result:
public static SKBitmap Rotate(SKBitmap bitmap, double angle)
{
double radians = Math.PI * angle / 180;
float sine = (float)Math.Abs(Math.Sin(radians));
float cosine = (float)Math.Abs(Math.Cos(radians));
int originalWidth = bitmap.Width;
int originalHeight = bitmap.Height;
int rotatedWidth = (int)(cosine * originalWidth + sine * originalHeight);
int rotatedHeight = (int)(cosine * originalHeight + sine * originalWidth);
var rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
using (var surface = new SKCanvas(rotatedBitmap))
{
surface.Translate(rotatedWidth / 2, rotatedHeight / 2);
surface.RotateDegrees((float)angle);
surface.Translate(-originalWidth / 2, -originalHeight / 2);
surface.DrawBitmap(bitmap, new SKPoint());
}
return rotatedBitmap;
}
In my case I used this when I needed rotate picture on the Xamarin.iOS platform (who ever tried this, knows), works like a charm.
I need to draw the most perfect circle possible. EmguCV seems to lack an anti-aliasing option.
I'm trying to use SmoothGaussian, but the circle still does not look good/smooth enough.
Also, the circle line intensity should have Gaussian shape (i.e.: brighter in the center).
How can I achieve that?
Here is what I'm doing now:
using (Image<Gray, Byte> img = new Image<Gray, byte>(800, 800, new Gray(0)))
{
PointF center = new PointF(img.Width / 2, img.Height / 2);
//Center line
float r = 200.0f;
CircleF circle = new CircleF(center, r);
img.Draw(circle, new Gray(255), 1);
img._SmoothGaussian(7, 7, 3, 3);
}
If you use Brg, Brga or Gray color you can use that hack:
using(var graph = Graphics.FromImage(image.Bitmap))
{
graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
graph.DrawEllipse(new Pen(color.BackColor), x, y, d`i`ameter, diameter);
}
`
Edit:
You can also use cvInvoke
var center = new Point(x, y);
var color = new Bgr(this.color.BackColor);
CvInvoke.cvCircle(image.Ptr, center, radius, color.MCvScalar, thickness, Emgu.CV.CvEnum.LINE_TYPE.CV_AA, 0);
`