/// <summary> /// Find rectangles in image and add possible rectangle candidates as temporary but known objects or updates /// existing objects from previous frames. /// </summary> /// <param name="occlusionTracking"></param> /// <param name="grayImage"></param> /// <param name="outputImage"></param> /// <param name="updateTime"></param> /// <param name="objects"></param> private RectangularObject[] FindRectangles(bool occlusionTracking, Image<Gray, byte> grayImage, ref Image<Rgb, byte> outputImage, DateTime updateTime, RectangularObject[] objects) { var newObjects = new List<RectangularObject>(); var imageWidth = grayImage.Width; var imageHeight = grayImage.Height; var pixels = imageWidth * imageHeight; var diagonal = Math.Sqrt(Math.Pow(imageWidth, 2) + Math.Pow(imageHeight, 2)); var maxRestoreDistance = (MaxRestoreDistance / 100.0) * diagonal; using (var storage = new MemStorage()) { for (var contours = grayImage.FindContours(CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, IsRetrieveExternal ? RETR_TYPE.CV_RETR_EXTERNAL : RETR_TYPE.CV_RETR_LIST, storage); contours != null; contours = contours.HNext) { var lowApproxContour = contours.ApproxPoly(contours.Perimeter * 0.015, storage); if (lowApproxContour.Area > ((MinContourArea / 100.0) * pixels) && lowApproxContour.Area < ((MaxContourArea / 100.0) * pixels)) //only consider contours with area greater than { if (IsRenderContent && IsDrawAllContours) outputImage.Draw(lowApproxContour, Rgbs.BlueTorquoise, 1); //outputImage.Draw(currentContour.GetConvexHull(ORIENTATION.CV_CLOCKWISE), Rgbs.BlueTorquoise, 2); // Continue with next contour if current contour is not a rectangle. List<DPoint> points; if (!IsPlausibleRectangle(lowApproxContour, MinAngle, MaxAngle, MinDetectRightAngles, out points)) continue; var highApproxContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage); if (IsRenderContent && IsDrawAllContours) outputImage.Draw(highApproxContour, Rgbs.Yellow, 1); var rectangle = highApproxContour.BoundingRectangle; var minAreaRect = highApproxContour.GetMinAreaRect(storage); var polygon = new Polygon(points.ToArray(), imageWidth, imageHeight); var contourPoints = highApproxContour.ToArray(); if (!UpdateObject(occlusionTracking, maxRestoreDistance, rectangle, minAreaRect, polygon, contourPoints, updateTime, objects)) { newObjects.Add(CreateObject(NextId(), rectangle, minAreaRect, polygon, contourPoints, updateTime)); } } } } return newObjects.ToArray(); }
/// <summary> /// Tries to find objects that are occluded. /// </summary> /// <param name="image"></param> /// <param name="updateTime"></param> /// <param name="outputImage"></param> /// <param name="objects"></param> private void UpdateOccludedObjects(Image<Rgb, byte> image, ref Image<Rgb, byte> outputImage, DateTime updateTime, RectangularObject[] objects) { var imageWidth = image.Width; var imageHeight = image.Height; var mask = new Image<Gray, byte>(imageWidth, imageHeight); var occludedObjects = objects.Where(o => !Equals(o.LastUpdate, updateTime)).ToArray(); // ignore if no objects are occluded but continue in case is render content set true to update debug view if (occludedObjects.Length < 1 && !IsRenderContent) return; foreach (var obj in occludedObjects) mask.Draw(obj.Shape, new Gray(1), -1); if (_depthImage == null) return; var occludedPartsImage = new Image<Gray, float>(imageWidth, imageHeight); var depthMapBinary = _depthImage.ThresholdBinaryInv(new Gray(255), new Gray(255)); var depthMap = depthMapBinary; if (depthMap.Width != imageWidth || depthMap.Height != imageHeight) { var resizedDepthMap = new Image<Gray, float>(imageWidth, imageHeight); CvInvoke.cvResize(depthMap.Ptr, resizedDepthMap.Ptr, INTER.CV_INTER_CUBIC); depthMap.Dispose(); depthMap = resizedDepthMap; } CvInvoke.cvCopy(depthMap.Ptr, occludedPartsImage.Ptr, mask); occludedPartsImage = occludedPartsImage.Erode(2).Dilate(2); var debugImage3 = occludedPartsImage.Convert<Rgb, byte>(); var fixedImage = image.Or(debugImage3); fixedImage = fixedImage.Dilate(2).Erode(2); var debugImage = fixedImage.Copy(); Task.Factory.StartNew(() => { var bitmapSource = debugImage.ToBitmapSource(true); debugImage.Dispose(); return bitmapSource; }).ContinueWith(t => DebugImageSource = t.Result); var outputImageEnclosed = outputImage; Parallel.ForEach(occludedObjects, obj => FindObjectByBlankingKnownObjects(true, fixedImage, ref outputImageEnclosed, updateTime, objects, obj)); }
/// <summary> /// Find an object by blanking out known objects except for the parameter object in the /// source image. If obj == null it will blank out all objects. /// </summary> /// <param name="occlusionTracking"></param> /// <param name="image"></param> /// <param name="outputImage"></param> /// <param name="objects"></param> /// <param name="obj"></param> /// <param name="updateTime"></param> private RectangularObject[] FindObjectByBlankingKnownObjects(bool occlusionTracking, Image<Rgb, byte> image, ref Image<Rgb, byte> outputImage, DateTime updateTime, RectangularObject[] objects, RectangularObject obj = null) { var objectsToBlank = obj != null ? objects.Where(o => o != obj) : objects; // Blank previous objects from previous frame var blankedImage = image.Copy(); foreach (var otherObject in objectsToBlank) { blankedImage.Draw(otherObject.Shape, Rgbs.Black, -1); } var blankedImageGray = blankedImage.Convert<Gray, Byte>(); var newObjects = FindRectangles(occlusionTracking, blankedImageGray, ref outputImage, updateTime, objects); blankedImageGray.Dispose(); return newObjects; }