private void FindDefects(Mat maskImage, ref int cx, ref int cy, int min_defects_count, int max_defects_count)
    {
        int erosion_size = 1;

        Mat element = Imgproc.getStructuringElement(
            Imgproc.MORPH_ELLIPSE,
            new Size(2 * erosion_size + 1, 2 * erosion_size + 1),
            new Point(erosion_size, erosion_size));

        // dilate and erode
        Imgproc.dilate(maskImage, maskImage, element);
        Imgproc.erode(maskImage, maskImage, element);
        element.Dispose();
        //Find Contours in image
        List <MatOfPoint> contours = new List <MatOfPoint>();

        Imgproc.findContours(maskImage, contours, new MatOfPoint(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

        //Loop to find the biggest contour; If no contour is found index=-1
        int    index = -1;
        double area  = 2000;

        for (int i = 0; i < contours.Count; i++)
        {
            var tempsize = Imgproc.contourArea(contours[i]);
            if (tempsize > area)
            {
                area  = tempsize;
                index = i;
            }
        }

        if (index == -1)
        {
            return;
        }
        else
        {
            var points = new MatOfPoint(contours[index].toArray());
            var hull   = new MatOfInt();
            Imgproc.convexHull(points, hull, false);

            var defects = new MatOfInt4();
            Imgproc.convexityDefects(points, hull, defects);

            var start_points = new MatOfPoint2f();
            var far_points   = new MatOfPoint2f();

            for (int i = 0; i < defects.size().height; i++)
            {
                int    ind_start = (int)defects.get(i, 0)[0];
                int    ind_end   = (int)defects.get(i, 0)[1];
                int    ind_far   = (int)defects.get(i, 0)[2];
                double depth     = defects.get(i, 0)[3] / 256;

                double a = Core.norm(contours[index].row(ind_start) - contours[index].row(ind_end));
                double b = Core.norm(contours[index].row(ind_far) - contours[index].row(ind_start));
                double c = Core.norm(contours[index].row(ind_far) - contours[index].row(ind_end));

                double angle = Math.Acos((b * b + c * c - a * a) / (2 * b * c)) * 180.0 / Math.PI;

                double threshFingerLength = ((double)maskImage.height()) / 8.0;
                double threshAngle        = 80;

                if (angle < threshAngle && depth > threshFingerLength)
                {
                    //start point
                    var aa = contours[index].row(ind_start);
                    start_points.push_back(contours[index].row(ind_start));
                    far_points.push_back(contours[index].row(ind_far));
                }
            }

            points.Dispose();
            hull.Dispose();
            defects.Dispose();

            // when no finger found
            if (far_points.size().height < min_defects_count || far_points.size().height > max_defects_count)
            {
                return;
            }

            var cnts = new List <MatOfPoint>();
            cnts.Add(contours[index]);

            Mat mm = new Mat();
            Imgproc.cvtColor(maskImage, mm, Imgproc.COLOR_GRAY2BGR);

            Imgproc.drawContours(mm, cnts, 0, new Scalar(0, 0, 255));
            // OpenCVForUnity.ImgcodecsModule.Imgcodecs.imwrite("D:/tempImg.jpg", mm)

            //var rotatedRect = Imgproc.minAreaRect(far_points);
            var boundingRect = Imgproc.boundingRect(far_points);

            cx = (int)(boundingRect.x + boundingRect.width / 2);
            cy = (int)(boundingRect.y + boundingRect.height / 2);
        }
    }