private ShapeClip DetectClip(CvSeq <CvPoint> contour, IplImage image) { // Approximate contours to rectange. CvMemStorage cstorage = new CvMemStorage(); CvSeq <CvPoint> verts = contour.ApproxPoly(CvContour.SizeOf, cstorage, ApproxPolyMethod.DP, contour.ContourPerimeter() * 0.05); CvRect rect = Cv.BoundingRect(verts); // scale BB CvSize originalSize = rect.Size; CvSize size = new CvSize((int)(rect.Width * 1.5), (int)(rect.Height * 1.5)); CvSize sizeDist = new CvSize(rect.Width - size.Width, rect.Height - size.Height); rect = new CvRect( Math.Max(rect.Location.X + sizeDist.Width / 2, 0), Math.Max(rect.Location.Y + sizeDist.Height / 2, 0), size.Width, size.Height); // If rect, convert to region of interest and approximate top. if (verts.Total >= 4 && new CvRect(0, 0, image.Width, image.Height).Contains(rect)) { DetectionState detectionState = verts.Total == 4 ? DetectionState.SemiOriented : DetectionState.Candidate; double angle = (180.0 / Math.PI) * ComputeOrientationFromVerts(verts.ToArray()); using (IplImage region = image.Clone(rect)) using (IplImage finalRegion = image.Clone(rect)) using (IplImage colorRegion = new IplImage(region.Size.Width, region.Size.Height, BitDepth.U8, 3)) using (IplImage debug = new IplImage(region.Size.Width + 20, region.Size.Height + 20, BitDepth.U8, 3)) { // Rotate into position based on the line angle estimate Cv.WarpAffine(region, region, Cv.GetRotationMatrix2D(new CvPoint2D32f(rect.Width / 2, rect.Height / 2), angle, 1)); Cv.FloodFill(region, new CvPoint(0, 0), 255, 0, 150); // Project image and find clusters region.Not(region); double[] horizontalProjection, verticalProjection; int[] horizontalPrjClusters = ComputeClusters(region, true, out horizontalProjection); int horizontalClusters = horizontalPrjClusters[0], lastHorizontalCluster = horizontalPrjClusters[1]; int[] verticalPrjClusters = ComputeClusters(region, false, out verticalProjection); int verticalClusters = verticalPrjClusters[0], lastVerticalCluster = verticalPrjClusters[1]; // Correct the orientation based on the clusters found bool foundLDRs = false; if (verticalClusters > horizontalClusters) { // 90 deg if (lastHorizontalCluster < region.Width / 2) { // 90deg angle += 90; foundLDRs = true; } else { // 270 deg angle += 270; foundLDRs = true; } } else if (verticalClusters < horizontalClusters) { // 0 deg if (lastVerticalCluster < region.Height / 2) { // 0deg foundLDRs = true; } else { // 180 deg angle += 180; foundLDRs = true; } } else { // something went wrong with our initial alignment // NO proper orientation found - could not identify the LDRs } #region DEBUG //debug.Zero(); //Cv.CvtColor(finalRegion, colorRegion, ColorConversion.GrayToRgb); //debug.DrawImage(20, 0, region.Width, region.Height, colorRegion); //for (int i = 0; i < region.Width / 2; i++) // debug.DrawRect(20 + i, debug.Height - (int)(horizontalProjection[i] * 100), 20 + i, debug.Height, CvColor.Red, 1); //for (int i = 0; i < region.Height / 2; i++) // debug.DrawRect(0, i, (int)(verticalProjection[i] * 100), i, CvColor.Red, 1); //debugWindow.ShowImage(debug); #endregion if (foundLDRs) { detectionState = DetectionState.FullyOriented; } } // Compute pixel space mapping Vec2F scale = new Vec2F(screenResolution.X / image.Width, screenResolution.Y / image.Height); return(new ShapeClip( detectionState, new Vec2F(rect.Location.X + 0.5f * rect.Width, rect.Location.Y + 0.5f * rect.Height).Scale(scale), new Vec2F(originalSize).Scale(scale), angle)); } else { return(null); } }