//Function to cross all informations added to this face and evaluate the best values
        public void Evaluate()
        {
            //Evaluate mouth
            evaluatedMouth = new Rect(0, 0, 0, 0);
            //Random randomizer = new Random();

            //evaluatedMouth = mouths[randomizer.Next(0, mouths.Count - 1)];

            //must work a few on the mouth to choose the best one and proceed to histogram check for try to determinate skin color, eye color, hair color etc..

            foreach (Rect mouth in mouths)
            {
                if (mouth.y < face.y + face.height / 2)
                    continue;

                if (evaluatedMouth.width > mouth.width)
                    continue;

                evaluatedMouth = mouth;
            }

            //Evaluate eyes
            evaluatedEyes = new ArrayList<Rect>();
            ArrayList<Rect> rightCandidates = new ArrayList<Rect>();
            ArrayList<Rect> leftCandidates = new ArrayList<Rect>();

            foreach (Rect eye in eyes)
            {
                //Ensure the eyes are in the upper half of the img region
                if (eye.y + eye.height / 2 > face.y + face.height / 2)
                    continue;

                if (eye.x + eye.width / 2 < face.x + face.width / 2)
                    rightCandidates.add(eye);
                else
                    leftCandidates.add(eye);
            }

            //get centers for each side weighted by their areas
            int totalAreas = 0;
            int totalX = 0;
            int totalY = 0;

            if (rightCandidates.size() > 0)
            {
                foreach (Rect eye in rightCandidates)
                {
                    int eyeArea = eye.width * eye.height;
                    totalAreas += eyeArea;

                    totalX += (eye.x + eye.width / 2) * eyeArea;
                    totalY += (eye.y + eye.height / 2) * eyeArea;
                }

                Point rightPoint = new Point(totalX / totalAreas, totalY / totalAreas);

                int rightEyeSide = (int)Math.Sqrt((double)totalAreas / (double)rightCandidates.size());

                Rect rightEye = new Rect(
                    rightPoint.x - rightEyeSide / 2,
                    rightPoint.y - rightEyeSide / 2,
                    rightEyeSide,
                    rightEyeSide);

                //rightEye.Offset(-rightEye.Width / 2, -rightEye.Height / 2);

                evaluatedEyes.add(rightEye);
            }

            if (leftCandidates.size() > 0)
            {
                totalAreas = 0;
                totalX = 0;
                totalY = 0;

                foreach (Rect eye in leftCandidates)
                {
                    int eyeArea = eye.width * eye.height;
                    totalAreas += eyeArea;

                    totalX += (eye.x + eye.width / 2) * eyeArea;
                    totalY += (eye.y + eye.height / 2) * eyeArea;
                }

                Point leftPoint = new Point(totalX / totalAreas, totalY / totalAreas);

                int leftEyeSide = (int)Math.Sqrt((double)totalAreas / (double)leftCandidates.size());

                Rect leftEye = new Rect(
                    leftPoint.x - leftEyeSide / 2,
                    leftPoint.y - leftEyeSide / 2,
                    leftEyeSide,
                    leftEyeSide);

                //leftEye.Offset(-leftEye.Width / 2, -leftEye.Height / 2);

                evaluatedEyes.add(leftEye);
            }

            //Check if it is valid
            isValid = false;

            if (evaluatedEyes.size() > 2)
                throw new Exception("Eyes count must be equal or less than two");

            if (evaluatedEyes.size() == 2)
            {
                isValid = true;

                //Get the face line data

                Point eye1Center = new Point(evaluatedEyes.get(0).x + evaluatedEyes.get(0).width / 2,
                    evaluatedEyes.get(0).y + evaluatedEyes.get(0).height / 2);

                Point eye2Center = new Point(evaluatedEyes.get(1).x + evaluatedEyes.get(1).width / 2,
                    evaluatedEyes.get(1).y + evaluatedEyes.get(1).height / 2);

                int xOffset = (eye2Center.x - eye1Center.x) / 2;
                int yOffset = (eye2Center.y - eye1Center.y) / 2;

                Point eyeLineCenter = new Point(eye1Center.x + xOffset, eye1Center.y + yOffset);

                int zeroDivFac = eye1Center.x == eye2Center.x ? 1 : 0;

                //Generate face line slope and offset
                double aFact = (double)(eye1Center.y - eye2Center.y) /
                    (double)(eye1Center.x - eye2Center.x + zeroDivFac);

                aFact = Math.Atan(aFact) + Math.PI / 2;
                aFact = Math.Tan(aFact);

                double bFact = eyeLineCenter.y - aFact * eyeLineCenter.x;

                faceLineSlope = aFact;
                faceLineOffset = bFact;

                //If the mouth is invalid, project a new based on the face line
                if (evaluatedMouth.width == 0)
                {
                    PointGenerator faceLinePoint = new PointGenerator(aFact, bFact);

                    Point projMouthPos = faceLinePoint.GetFromY(face.y + face.height * 0.8);

                    evaluatedMouth = new Rect(
                        projMouthPos.x - (face.width / 3) / 2,
                        projMouthPos.y - (face.height / 5) / 2,
                        face.width / 3,
                        face.height / 5);

                    //evaluatedMouth.Offset(-evaluatedMouth.Width / 2, -evaluatedMouth.Height / 2);
                }
            }

            if (evaluatedEyes.size() == 1 && evaluatedMouth.width > 0)
            {
                isValid = true;

                //Project the other eye based on the mouth

                //Get the bottom mouth coords
                Point mouthBottomCenter = new Point(
                    evaluatedMouth.x + evaluatedMouth.width / 2,
                    evaluatedMouth.y + evaluatedMouth.height);

                //get the facetop coords
                Point faceTopCenter = new Point(face.width / 2 +
                    face.x, face.y);

                //Apply an experimental correct factor to the values
                int correctFact = mouthBottomCenter.x - faceTopCenter.x;
                //correctFact = (int)(correctFact * 0.5);

                mouthBottomCenter.x += correctFact;
                faceTopCenter.x -= correctFact;

                //Get the slope of the faceline

                //In case they are the same value, add a pixel to prevent division by 0
                int zeroDivFac = mouthBottomCenter.x == faceTopCenter.x ? 1 : 0;

                double a = (double)(mouthBottomCenter.y - faceTopCenter.y) /
                        (double)(mouthBottomCenter.x - faceTopCenter.x + zeroDivFac);

                //Get the offset of the face line
                double b = mouthBottomCenter.y - a * mouthBottomCenter.x;

                faceLineSlope = a;
                faceLineOffset = b;

                //Get the line function of the face
                PointGenerator faceLinePoint = new PointGenerator(a, b);

                //Get the reference of the existing eye and its center point
                Rect eyeRef = evaluatedEyes.get(0);
                Point eyeCenter = new Point(eyeRef.x + eyeRef.width / 2, eyeRef.y + eyeRef.height / 2);

                //Get the slope of the eye line (it must be normal to the face line, so we turn it Pi/2
                double aEyeFact = Math.Atan(a) + Math.PI / 2;
                aEyeFact = Math.Tan(aEyeFact);

                //Get the eye line offset
                double bEyeFact = eyeCenter.y - aEyeFact * eyeCenter.x;

                //Get the line function of the eye
                PointGenerator eyeLinePoint = new PointGenerator(aEyeFact, bEyeFact);

                //Get the horizontal difference between the center of the existing eye and the face line
                int diff = faceLinePoint.GetFromY(eyeCenter.y).x - eyeCenter.x;

                //Get the project eye coords
                Point projEyePoint = eyeLinePoint.GetFromX(eyeCenter.x + diff * 2);

                //Get the project eye rectangle
                Rect projEyeRect = new Rect(
                    projEyePoint.x - eyeRef.width / 2,
                    projEyePoint.y - eyeRef.height / 2,
                    eyeRef.width,
                    eyeRef.height);
                //projEyeRect.Offset(-eyeRef.Width / 2, -eyeRef.Height / 2);

                evaluatedEyes.add(projEyeRect);
            }

            //If the face keep invalid, put the face line on the middle of the face square
            if (!isValid)
            {
                faceLineSlope = -face.height / 0.01;
                faceLineOffset = face.y - faceLineSlope * face.x + face.width / 2;
            }
        }
        public Rect GetNose()
        {
            PointGenerator faceLinePoint = new PointGenerator(faceLineSlope, faceLineOffset);

            Size noseSize = new Size(face.width / 7, face.height / 7);

            Point projNosePos = faceLinePoint.GetFromY(evaluatedMouth.y - noseSize.height);

            Rect createdNose = new Rect(
                projNosePos.x - noseSize.width / 2,
                projNosePos.y - noseSize.height / 2,
                noseSize.width,
                noseSize.height);

            return createdNose;
        }
Exemple #3
0
        void drawFaceRectangles(PersonFace personFace, Mat featureImage)
        {
            Rect faceRect = personFace.GetFace();
            Rect mouthRect = personFace.GetMouth();
            Rect noseRect = personFace.GetNose();
            Rect[] eyesRects = personFace.GetEyes();

            double[] faceLineData = personFace.GetFaceLineData();
            PointGenerator faceLine = new PointGenerator(faceLineData[0], faceLineData[1]);
            Point faceTopPoint = faceLine.GetFromY(faceRect.y);
            Point faceBottomPoint = faceLine.GetFromY(faceRect.y + faceRect.height);

            //Draw face line
            Imgproc.line(featureImage, faceTopPoint, faceBottomPoint, new Scalar(255, 0, 0), 1);

            //Draw rect around the face
            Imgproc.rectangle(featureImage, faceRect, new Scalar(0, 255, 255), 2);

            //Draw circle around face
            Point faceCenter = new Point(faceRect.x + faceRect.width / 2, faceRect.y + faceRect.height / 2);
            Size faceSize = new Size(faceRect.width / 2, faceRect.height / 2);
            Imgproc.ellipse(featureImage, faceCenter,faceSize,0,0,360,new Scalar(172, 203, 227),0);
            Imgproc.ellipse(featureImage, faceCenter, faceSize, 0, 0, 360,new Scalar(0,0,0), 1);

            //Draw rect around the mouth
            Imgproc.rectangle(featureImage, mouthRect, new Scalar(0, 255, 255), 1);

            //Draw rect around the nose
            Imgproc.rectangle(featureImage, noseRect, new Scalar(0, 255, 255), 1);

            //Draw eyes rect and circles
            for (var i = 0; i < eyesRects.Length; i++)
            {
                Rect eye = eyesRects[i];
                Imgproc.rectangle(featureImage, eye, new Scalar(0, 255, 255), 1);
            }

            imageBox2.Image = featureImage;
        }
Exemple #4
0
        void detectHair(PersonFace personFace, Mat hairImage)
        {
            Rect faceRect = personFace.GetFace();

            double adjWidth = faceRect.width * 0.85;
            double adjHeight = faceRect.height * 1.2;
            double adjX = faceRect.x + (faceRect.width - adjWidth) / 2;
            double adjY = faceRect.y + (faceRect.height - adjHeight) / 2;

            Rect adjFaceRect = new Rect((int)adjX, (int)adjY, (int)adjWidth, (int)adjHeight);

            double[] faceLineData = personFace.GetFaceLineData();
            PointGenerator faceLine = new PointGenerator(faceLineData[0], faceLineData[1]);
            Point faceTopPoint = faceLine.GetFromY(adjFaceRect.y);
            Point faceBottomPoint = faceLine.GetFromY(adjFaceRect.y + adjFaceRect.height);

            //Draw face line
            //Imgproc.line(hairImage, faceTopPoint, faceBottomPoint, new Scalar(255, 0, 0), 2);

            //Get face feature angle
            double faceFeatureAngle = Math.Atan(faceLineData[0]);
            faceFeatureAngle = RadianToDegree(faceFeatureAngle);
            faceFeatureAngle += faceFeatureAngle > 0 ? -90 : 90;

            //Imgproc.rectangle(hairImage, adjFaceRect, new Scalar(0, 255, 255), 2);

            /*Imgproc.ellipse(hairImage,
                new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                new Size(adjFaceRect.width/2, adjFaceRect.height/2), faceFeatureAngle, 0, 360, new Scalar(255, 0, 0), 2);

            Imgproc.ellipse(hairImage,
                new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                new Size((int)(adjFaceRect.width / 1.8), (int)(adjFaceRect.height / 1.8)), faceFeatureAngle, 0, 360, new Scalar(255, 0, 0), 2);*/

            Mat[] imgComponents = hairImage.Split();

            for (int i = 0; i < 5; i++)
            {
                double factor = 1.8 - i * 0.2;

                Mat maskImage = new Image<Gray, byte>(hairImage.width(), hairImage.height(), new Gray(0)).Mat;

                Imgproc.ellipse(maskImage,
                    new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                    new Size((int)(adjFaceRect.width / factor), (int)(adjFaceRect.height / factor)), faceFeatureAngle + 180, 0, 180, new Scalar(255), -1);

                Imgproc.ellipse(maskImage,
                    new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                    new Size(adjFaceRect.width / 2, adjFaceRect.height / 2), faceFeatureAngle, 0, 360, new Scalar(0), -1);

                //imageBox13.Image = maskImage;

                Mat testImg = new Mat();

                hairImage.CopyTo(testImg, maskImage);

                imageBox13.Image = testImg;

                Stack<string> titleStack = new Stack<string>();
                titleStack.Push("Red");
                titleStack.Push("Green");
                titleStack.Push("Blue");

                HistogramForm histForm = new HistogramForm();

                foreach (Mat img in imgComponents)
                {
                    //try histogram only the upper half to detect the most probable hair color range

                    Mat hist = new Mat();
                    CvInvoke.CalcHist(new VectorOfMat(img), new int[] { 0 }, maskImage, hist, new int[] { 256 }, new float[] { 0, 255 }, false);

                    string color = titleStack.Pop();

                    histForm.AddHist(hist, color, System.Drawing.Color.FromName(color));

                    /*byte[] testBuffer = new byte[256];
                    hist.CopyTo(testBuffer);

                    string msg = "";

                    foreach (byte value in testBuffer)
                        msg += value + " ";

                    msg += Environment.NewLine;
                    msg += Environment.NewLine;

                    textBox1.AppendText(msg);*/

                }

                histForm.Show(i.ToString());

            }

            Image<Bgr, byte> testImg2 = new Image<Bgr, byte>(hairImage.Bitmap);

            imageBox13.Image = testImg2.InRange(new Bgr(25, 25, 25), new Bgr(100, 85, 100));

            //createHistogram(new Image<Bgr, byte>(maskImage.Bitmap), 256, "teste");

            /*Imgproc.ellipse(hairImage,
                new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                new Size((int)(adjFaceRect.width / 1.6), (int)(adjFaceRect.height / 1.6)), faceFeatureAngle, 0, 360, new Scalar(255, 0, 0), 2);

            Imgproc.ellipse(hairImage,
                new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                new Size((int)(adjFaceRect.width / 1.4), (int)(adjFaceRect.height / 1.4)), faceFeatureAngle, 0, 360, new Scalar(255, 0, 0), 2);

            Imgproc.ellipse(hairImage,
                new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                new Size((int)(adjFaceRect.width / 1.2), (int)(adjFaceRect.height / 1.2)), faceFeatureAngle, 0, 360, new Scalar(255, 0, 0), 2);

            Imgproc.ellipse(hairImage,
                new Point(adjFaceRect.x + adjFaceRect.width / 2, adjFaceRect.y + adjFaceRect.height / 2),
                new Size((int)(adjFaceRect.width / 1), (int)(adjFaceRect.height / 1)), faceFeatureAngle, 0, 360, new Scalar(255, 0, 0), 2);*/
        }
Exemple #5
0
        void drawFaceFeatures(PersonFace personFace, Mat illustratedImg)
        {
            Rect faceRect = personFace.GetFace();
            Rect mouthRect = personFace.GetMouth();
            Rect noseRect = personFace.GetNose();
            Rect[] eyesRects = personFace.GetEyes();

            //Draw face division line
            double[] faceLineData = personFace.GetFaceLineData();
            PointGenerator faceLine = new PointGenerator(faceLineData[0], faceLineData[1]);
            Point faceTopPoint = faceLine.GetFromY(faceRect.y);
            Point faceBottomPoint = faceLine.GetFromY(faceRect.y + faceRect.height);

            //Imgproc.line(illustratedImg, faceTopPoint, faceBottomPoint, new Scalar(255, 0, 0), 1);

            //Get face feature angle
            double faceFeatureAngle = Math.Atan(faceLineData[0]);
            faceFeatureAngle = RadianToDegree(faceFeatureAngle);
            faceFeatureAngle += faceFeatureAngle > 0 ? -90 : 90;

            //Draw face lateral boundaries lines
            //Detect right and left eye
            Rect rightEye, leftEye;
            if (eyesRects[0].x > eyesRects[1].x)
            {
                rightEye = eyesRects[1];
                leftEye = eyesRects[0];
            }
            else
            {
                rightEye = eyesRects[0];
                leftEye = eyesRects[1];
            }

            //get eye line generator
            PointGenerator eyeLines = new PointGenerator(
                getRectCenter(rightEye), getRectCenter(leftEye));

            Point leftFacePoint = eyeLines.GetFromX(getRectCenter(leftEye).x + leftEye.width);
            Point rightFacePoint = eyeLines.GetFromX(getRectCenter(rightEye).x - rightEye.width);

            /* CvInvoke.Circle(image, leftFacePoint, 20,
                 new Bgr(Color.Green).MCvScalar, -1);

             CvInvoke.Circle(image, rightFacePoint, 20,
                 new Bgr(Color.Blue).MCvScalar, -1);*/

            //Get line generators for each side of the face
            double faceLineSlope = faceLineData[0];

            //Left side
            double leftFaceSideOffset = leftFacePoint.y - leftFacePoint.x * faceLineSlope;
            PointGenerator leftFaceLine = new PointGenerator(faceLineSlope, leftFaceSideOffset);

            Point startPointL = leftFaceLine.GetFromY(0);
            Point endPointL = leftFaceLine.GetFromY(illustratedImg.Height);

            //Right side
            double rightFaceSideOffset = rightFacePoint.y - rightFacePoint.x * faceLineSlope;
            PointGenerator rightFaceLine = new PointGenerator(faceLineSlope, rightFaceSideOffset);

            Point startPointR = rightFaceLine.GetFromY(0);
            Point endPointR = rightFaceLine.GetFromY(illustratedImg.Height);

            //Imgproc.line(illustratedImg, startPointL, endPointL, new Scalar(0,255,0), 5);
            //Imgproc.line(illustratedImg, startPointR, endPointR,new Scalar(255,0,0), 3);

            //Draw mouth line
            //Put center on the top for the mouth stay in the middle of the mouth square
            Point mouthCenter = new Point(mouthRect.x + mouthRect.width / 2, mouthRect.y);
            Size mouthSize = new Size(mouthRect.width / 2, mouthRect.height / 2);

            Point mCenter = getRectCenter(mouthRect);

            //Get mouth line generator
            double aFactMouth = Math.Tan(Math.Atan(faceLineSlope) + Math.PI / 2);
            double bfactMouth = mCenter.y - mCenter.x * aFactMouth;
            PointGenerator mouthLine = new PointGenerator(aFactMouth, bfactMouth);

            double leftFaceMouthCrossX = (bfactMouth - leftFaceSideOffset) /
                (faceLineSlope - aFactMouth);

            double rightFaceMouthCrossX = (bfactMouth - rightFaceSideOffset) /
                (faceLineSlope - aFactMouth);

            Point leftFaceMouthCross = mouthLine.GetFromX(leftFaceMouthCrossX);
            Point rightFaceMouthCross = mouthLine.GetFromX(rightFaceMouthCrossX);

            //Get face top line
            double afactTopFace = aFactMouth;   //use the mouth line since this uses the same slope
            double bfactTopFace = faceTopPoint.y - faceTopPoint.x * afactTopFace;
            PointGenerator faceTopLine = new PointGenerator(afactTopFace, bfactTopFace);

            double leftTopFaceCrossX = (bfactTopFace - leftFaceSideOffset) /
                 (faceLineSlope - afactTopFace);

            double rightTopFaceCrossX = (bfactTopFace - rightFaceSideOffset) /
                (faceLineSlope - afactTopFace);

            Point leftTopFaceCross = faceTopLine.GetFromX(leftTopFaceCrossX);
            Point rightTopFaceCross = faceTopLine.GetFromX(rightTopFaceCrossX);

            /*CvInvoke.Circle(illustratedImg, leftTopFaceCross, 5, new MCvScalar(), -1);
            CvInvoke.Circle(illustratedImg, rightTopFaceCross, 5, new MCvScalar(), -1);
            CvInvoke.Circle(illustratedImg, leftFaceMouthCross, 5, new MCvScalar(), -1);
            CvInvoke.Circle(illustratedImg, rightFaceMouthCross, 5, new MCvScalar(), -1);
            CvInvoke.Circle(illustratedImg, faceBottomPoint, 5, new MCvScalar(), -1);*/

            MatOfPoint facePointsMat = new MatOfPoint(leftTopFaceCross,
                rightTopFaceCross,
                rightFaceMouthCross,
                faceBottomPoint,
                leftFaceMouthCross);

            //CvInvoke.Polylines(image, facePointsVector, true, new Bgr(172, 203, 227).MCvScalar, 1);

            Imgproc.fillConvexPoly(illustratedImg, facePointsMat, new Scalar(255,255,255));

            Imgproc.ellipse(illustratedImg, mouthCenter, mouthSize, faceFeatureAngle, 0, 180, new Scalar(0,0,0), 2);

            Point p1 = faceTopLine.GetFromX(0);
            Point p2 = faceTopLine.GetFromX(illustratedImg.Width);

            //Imgproc.line(illustratedImg, p1, p2, new Scalar(0, 0, 0), 3);

            //Draw nose line
            Point noseCenter = new Point(noseRect.x + noseRect.width / 2,
                noseRect.y + noseRect.height / 2);
            Size noseSize = new Size(noseRect.width / 2, noseRect.height / 2);
            double noseAngle = Math.Atan(faceLineData[0]);
            noseAngle = RadianToDegree(noseAngle);

            Imgproc.ellipse(illustratedImg, noseCenter, noseSize, noseAngle, 0, 180, new Scalar(0, 0, 0), 2);

            //Draw eyes ellipses
            foreach (Rect eye in personFace.GetEyes())
            {
                Point eyeCenter = new Point(eye.x + eye.width / 2, eye.y + eye.height / 2);
                Size ellipseSize = new Size(eye.width / 5, eye.height / 2);

                Imgproc.ellipse(illustratedImg, eyeCenter, ellipseSize, faceFeatureAngle, 0, 360, new Scalar(0, 0, 0), -1);
            }

            Imgproc.line(illustratedImg, faceBottomPoint, new Point(illustratedImg.width() / 2, illustratedImg.height()), new Scalar(0, 0, 0));
        }