/// <summary> /// Finds the contours with minimum perimeters. /// </summary> /// <param name="image"></param> /// <param name="hand">Can be null.</param> private void FindContours(Joint hand) { // Non-zero pixels are treated as 1s. Source image content is modifield. CvInvoke.cvFindContours(HandMask.Ptr, storage, ref contourPtr, StructSize.MCvContour, RETR_TYPE.CV_RETR_EXTERNAL, CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, new Point(0, 0)); var contour = new Seq <Point>(contourPtr, null); float z = DefaultZDist; if (hand != null) { z = hand.Position.Z; } HandCandidates.Clear(); double perimThresh = DepthUtil.GetDepthImageLength(width, HandWidth, z) * 2; for (; contour != null && contour.Ptr.ToInt32() != 0; contour = contour.HNext) { var perim = CvInvoke.cvContourPerimeter(contour.Ptr); if (perim > perimThresh) { HandMask.Draw(contour, new Gray(255), -1); HandCandidates.Add(contour.BoundingRectangle); } } }
/// <summary> /// </summary> /// <returns></returns> Rectangle ComputeInitialRect(float z) { if (InterestPoints.Count > 0) { int x = 0, y = 0; foreach (Point ip in InterestPoints) { x += ip.X; y += ip.Y; } x /= InterestPoints.Count; y /= InterestPoints.Count; double xx = 0, yy = 0; foreach (Point ip in InterestPoints) { xx += (ip.X - x) * (ip.X - x); yy += (ip.Y - y) * (ip.Y - y); } xx /= InterestPoints.Count; yy /= InterestPoints.Count; xx = Math.Sqrt(xx); yy = Math.Sqrt(yy); var scaledHandWidth = DepthUtil.GetDepthImageLength(width, HandWidth, z); var rectWidth = (int)Math.Max(xx, scaledHandWidth); var rectHeight = (int)Math.Max(yy, scaledHandWidth); return(new Rectangle(x - rectWidth / 2, y - rectHeight / 2, rectWidth, rectHeight)); } return(HandRect); }
/// <summary> /// Computes initial hand searching rectangle in the depth image. If the point is out side of /// the frame boundary, an empty rectangle will be returned. /// </summary> /// <returns></returns> Rectangle ComputeInitialRect(DepthImagePoint point, float z) { var scaledHandWidth = DepthUtil.GetDepthImageLength(width, HandWidth, z) * 2; var left = Math.Max(0, (int)(point.X - scaledHandWidth / 2)); left = Math.Min(left, width); var top = Math.Max(0, (int)(point.Y - scaledHandWidth / 2)); top = Math.Min(top, height); // right and bottom are exclusive. var right = Math.Min(width, (int)(left + scaledHandWidth)); var bottom = Math.Min(height, (int)(top + scaledHandWidth)); var rectWidth = right - left; var rectHeight = bottom - top; if (rectWidth <= 0 || rectHeight <= 0) { return(Rectangle.Empty); } return(new Rectangle(left, top, right - left, bottom - top)); }
/// <summary> /// If no bounding box is found, returns the last bounding box. /// </summary> /// <returns></returns> List <Rectangle> FindBestBoundingBox(short[] depthFrame, Skeleton skeleton) { CvInvoke.cvConvert(SaliencyProb.Ptr, TempMask.Ptr); // Non-zero pixels are treated as 1s. Source image content is modifield. CvInvoke.cvFindContours(TempMask.Ptr, storage, ref contourPtr, StructSize.MCvContour, RETR_TYPE.CV_RETR_EXTERNAL, CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, new Point(0, 0)); var contour = new Seq <Point>(contourPtr, null); SortedList <float, Seq <Point> > bestContours = new SortedList <float, Seq <Point> >(); List <Rectangle> bestBoundingBoxes = new List <Rectangle>(); float z = DefaultZDist; var hand = SkeletonUtil.GetJoint(skeleton, JointType.HandRight); if (hand != null) { z = hand.Position.Z; } double perimThresh = DepthUtil.GetDepthImageLength(width, HandWidth, z) * 2; FaceModel = SkeletonUtil.GetFaceModel(skeleton, mapper); for (; contour != null && contour.Ptr.ToInt32() != 0; contour = contour.HNext) { var perim = CvInvoke.cvContourPerimeter(contour.Ptr); if (perim > perimThresh) { var rect = contour.BoundingRectangle; var score = ContourScore(rect); var center = rect.Center(); int x = (int)center.X; int y = (int)center.Y; var depth = DepthUtil.RawToDepth(depthFrame[y * width + x]); if (!FaceModel.IsPartOfFace(x, y, depth) && (bestContours.Count < NumTrackedHands || score > bestContours.ElementAt(0).Key)) { bestContours.Add(score, contour); if (bestContours.Count > NumTrackedHands) { bestContours.RemoveAt(0); } } } } if (bestContours.Count > 0) { foreach (var c in bestContours.Values) { var rect = c.BoundingRectangle; CvInvoke.cvCamShift(TrackedDepthFrame.Ptr, rect, new MCvTermCriteria(CamShiftIter), out connectedComp, out shiftedBox); var bestBoundingBox = shiftedBox.MinAreaRect(); bestBoundingBoxes.Add(bestBoundingBox); //FloodFill(TrackedDepthFrame, bestBoundingBox); //if (bestBoundingBox.Width > 0) { // TempMask.ROI = bestBoundingBox; // CvInvoke.cvFindContours(TempMask.Ptr, storage, ref contourPtr, StructSize.MCvContour, // RETR_TYPE.CV_RETR_EXTERNAL, CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, // new Point(0, 0)); // contour = new Seq<Point>(contourPtr, null); // Seq<Point> largestContour = null; // var maxPerim = perimThresh; // for (; contour != null && contour.Ptr.ToInt32() != 0; contour = contour.HNext) { // var perim = CvInvoke.cvContourPerimeter(contour.Ptr); // if (perim > maxPerim) { // maxPerim = perim; // largestContour = contour; // } // } // CvInvoke.cvZero(TempMask.Ptr); // if (largestContour != null) // TempMask.Draw(largestContour, new Gray(255), -1); // FilterImage(TrackedDepthFrame, TempMask); // TempMask.ROI = Rectangle.Empty; //} } } return(bestBoundingBoxes); }