private Rectangle FindCoveringRectangle(List <Pixel> boundary) { if (boundary == null) { return(null); } int[] min = new int[2] { _image.LenX - 1, _image.LenY - 1 }; int[] max = new int[2] { 0, 0 }; foreach (var pix in boundary) { if (pix.X < min[0]) { min[0] = pix.X; } if (pix.X > max[0]) { max[0] = pix.X; } if (pix.Y < min[1]) { min[1] = pix.Y; } if (pix.Y > max[1]) { max[1] = pix.Y; } } var coveringRectangle = new Rectangle( _image.GetArrayElement(min[0], min[1]), _image.GetArrayElement(max[0], max[1]), _image.GetArrayElement(min[0], max[1]), _image.GetArrayElement(max[0], min[1]) ); return(coveringRectangle); }
private ClockWise _direction; // index to keep where are we in the clock-wise clock // 0 - w, 1 - nw, 2 - n, 3 - ne, 4 - e, 5 - se, 6 - s, 7 - sw private Pixel GetClockWisePixel(Pixel input, ImageMatrix img) { int newX, newY; do { var x_offset = _directionOffset[(int)_direction, 0]; var y_offset = _directionOffset[(int)_direction, 1]; _direction = (ClockWise)((int)(_direction + 1) % 8); newX = input.X + x_offset; newY = input.Y + y_offset; } // if edge pixels, move to next clockwise while (newX < 0 || newX >= img.LenX || newY < 0 || newY >= img.LenY); return(img.GetArrayElement(newX, newY)); }
public IEnumerator <Pixel> GetEnumerator() { // use local variables to be restarted in the next foreach statement var upperBound = _upperBound; var bottomBound = _bottomBound; var leftBound = _leftBound; var rightBound = _rightBound; var counter = _counter; var x = _x; var y = _y; upperBound++; // initial increase of boundary so while (counter > 0) { // go right until you hit boundary while (y < rightBound) { yield return(_image.GetArrayElement(x, y)); y++; counter--; } rightBound--; // go down until you hit boundary while (x < bottomBound) { yield return(_image.GetArrayElement(x, y)); x++; counter--; } bottomBound--; // go left until you hit boundary while (y > leftBound) { yield return(_image.GetArrayElement(x, y)); y--; counter--; } leftBound++; // go up until you hit boundary while (x > upperBound) { yield return(_image.GetArrayElement(x, y)); x--; counter--; } upperBound++; } yield return(_image.GetArrayElement(x, y)); // last element when all bounds are same... }
public List <Pixel> Trace(ImageMatrix img) { Pixel firstHolePixel; for (int i = 0; i < img.LenX; i++) { for (int j = 0; j < img.LenY; j++) { firstHolePixel = img.GetArrayElement(i, j); if (firstHolePixel.Value == -1) { // while goto statements are not highly approved of, as they create hard-to-read spaghetti code, // this (breaking out of nested loops) is one of the rare cases where they should be used, // as they are more coherent than setting up multiple flags, or using sub-methods that will return. goto Hole_Exists; } } } // if here - no hole was found, simply return null return(null); Hole_Exists: ClockWise _start; // how we first start the trip _direction = ClockWise.West; // initial position var holePixel = firstHolePixel; // What if hole is in (x,0) ? We'll go around it clockwise until we find a non-hole pixel if (holePixel.Y == 0) { var nextPixel = GetClockWisePixel(holePixel, img); while (nextPixel.Value == -1) { Backtrack(); holePixel = nextPixel; nextPixel = GetClockWisePixel(holePixel, img); if (holePixel == firstHolePixel) // entire image is one big hole { return(null); } } _direction = (ClockWise)((int)(_direction + 7) % 8); } _start = _direction; var Boundary = new List <Pixel>(); var firstPixel = GetClockWisePixel(holePixel, img); Boundary.Add(firstPixel); var boundaryPixel = GetClockWisePixel(holePixel, img); // stop condition: // A. reach the same first pixel we started from // B. in cases of enclaves with 1 space gap, this might cause a premature stop // we can make sure we are reaching it while completeing the full circle of the circle-wise turning // (also called Jacob's stopping criteria) while (!(boundaryPixel == firstPixel && _direction - 1 == _start)) { if (boundaryPixel.Value != -1) { if (!Boundary.Contains(boundaryPixel)) { Boundary.Add(boundaryPixel); } } else { Backtrack(); holePixel = boundaryPixel; } boundaryPixel = GetClockWisePixel(holePixel, img); } return(Boundary); }