protected void RemoveVisualChildren(ICollection coll) { foreach (object obj in coll) { Darwin.Point point = obj as Darwin.Point; if (point != null) { RemoveVisualChild(point); } } }
protected void CreateVisualChild(Darwin.Point point) { DrawingVisualPlus drawingVisual = new DrawingVisualPlus(); drawingVisual.DataPoint = point; DrawingContext dc = drawingVisual.RenderOpen(); switch (point.Type) { case PointType.Chopping: dc.DrawEllipse(Brushes[1], null, new System.Windows.Point(point.X / ContourScale + XOffset, point.Y / ContourScale + YOffset), PointSize, PointSize); break; case PointType.Feature: dc.DrawEllipse(Brushes[2], null, new System.Windows.Point(point.X / ContourScale + XOffset, point.Y / ContourScale + YOffset), FeaturePointSize, FeaturePointSize); break; case PointType.FeatureMoving: dc.DrawEllipse(Brushes[1], null, new System.Windows.Point(point.X / ContourScale + XOffset, point.Y / ContourScale + YOffset), FeaturePointSize, FeaturePointSize); break; case PointType.Normal: default: dc.DrawEllipse(Brushes[0], null, new System.Windows.Point(point.X / ContourScale + XOffset, point.Y / ContourScale + YOffset), PointSize, PointSize); break; } if (point.Type == PointType.Moving && Pens != null) { DrawMovingLines(point, dc); } //drawingVisual.Transform = new TranslateTransform(RenderSize.Width * dataPoint.X, // RenderSize.Height * dataPoint.Y); dc.Close(); // If it's a feature point, add it, otherwise insert so the Feature points have // the highest ZIndex if (point.Type == PointType.Feature || point.Type == PointType.FeatureMoving) { visualChildren.Add(drawingVisual); } else { visualChildren.Insert(0, drawingVisual); } }
protected void RemoveVisualChild(Darwin.Point point) { List <DrawingVisualPlus> removeList = new List <DrawingVisualPlus>(); foreach (Visual child in visualChildren) { DrawingVisualPlus drawingVisual = child as DrawingVisualPlus; if (drawingVisual.DataPoint == point) { removeList.Add(drawingVisual); break; } } foreach (DrawingVisualPlus drawingVisual in removeList) { visualChildren.Remove(drawingVisual); } }
private void DrawMovingLines(Darwin.Point dataPoint, DrawingContext dc) { var pointIndex = ItemsSource.IndexOf(dataPoint); if (pointIndex >= 0) { if (pointIndex >= 1) { dc.DrawLine(Pens[0], new System.Windows.Point(ItemsSource[pointIndex - 1].X / ContourScale + XOffset, ItemsSource[pointIndex - 1].Y / ContourScale + YOffset), new System.Windows.Point(dataPoint.X / ContourScale + XOffset, dataPoint.Y / ContourScale)); } if (pointIndex < ItemsSource.Count - 1) { dc.DrawLine(Pens[0], new System.Windows.Point(ItemsSource[pointIndex + 1].X / ContourScale + XOffset, ItemsSource[pointIndex + 1].Y / ContourScale + YOffset), new System.Windows.Point(dataPoint.X / ContourScale + XOffset, dataPoint.Y / ContourScale + YOffset)); } } }
protected void OnItemPropertyChanged(object sender, ItemPropertyChangedEventArgs args) { Darwin.Point point = args.Item as Darwin.Point; RemoveVisualChild(point); CreateVisualChild(point); //foreach (Visual child in visualChildren) //{ // DrawingVisualPlus drawingVisual = child as DrawingVisualPlus; // if (dataPoint == drawingVisual.DataPoint) // { // if (dataPoint.Type == PointType.Moving) // { // dc.DrawEllipse(Brushes[0], null, new System.Windows.Point(dataPoint.X, dataPoint.Y), 3, 3); // if (dataPoint.Type == PointType.Moving && Pens != null) // { // DrawMovingLines(dataPoint, dc); // } // } // // Assume only VariableX or VariableY are changing // TranslateTransform xform = drawingVisual.Transform as TranslateTransform; // if (xform != null) // { // if (args.PropertyName == "X") // xform.X = RenderSize.Width * dataPoint.X; // else if (args.PropertyName == "Y") // xform.Y = RenderSize.Height * dataPoint.Y; // } // } //} }
public static System.Drawing.Point ToDrawingPoint(this Darwin.Point point) { return(new System.Drawing.Point(point.X, point.Y)); }
public static bool MoveContour( ref Contour contour, // The contour we'd like to move DirectBitmap edgeImage, // Edge strength image used for energy calculations int neighborhoodSize, // Neighborhood window size // neighborhoodSize x neighborhoodSize float[] energyWeights ) { if (contour == null) { throw new ArgumentNullException(nameof(contour)); } if (edgeImage == null) { throw new ArgumentNullException(nameof(edgeImage)); } if (neighborhoodSize <= 0) { throw new ArgumentOutOfRangeException(nameof(neighborhoodSize)); } int minPosition = 0, // keeps track of the value of k (the current node) // corresponding to the minimum energy found so far // in the search using k over all neighbors of the // current node // It's initialized to zero because there's a (very) // slight chance that it could be used unitialized // otherwise numNeighbors; float minEnergy, // keeps track of the minimum energy found so far // in the search using k over all neighbors of the // current node. energy; // is used in the search over the neighbors of the // current node as a temporary storage of the energy computed System.Drawing.Point nextNode = new System.Drawing.Point(), // contains the coordinates, for the neighbor of the // next node indexed by j. These coordinates are used // only to compute the energy associated with the // associated choice of snaxel positions currNode = new System.Drawing.Point(); // contains the coordinates, for the neighbor of the // current node indexed by k. These coordinates are // used only to compute the energy associated with the // associated choice of snaxel positions numNeighbors = neighborhoodSize * neighborhoodSize; int numPoints = contour.NumPoints; if (numPoints <= 2) { return(false); } float[,] energyMtx = new float[numPoints - 1, numNeighbors]; int[,] posMtx = new int[numPoints - 1, numNeighbors]; System.Drawing.Point[] neighbor = new System.Drawing.Point[numNeighbors]; for (int a = 0; a < numNeighbors; a++) { neighbor[a].X = (a % neighborhoodSize) - (neighborhoodSize - 1) / 2; neighbor[a].Y = (a / neighborhoodSize) - (neighborhoodSize - 1) / 2; } // initialize first column of energy matrix // This block of code simply sets the first column of the energy // matrix to zero, since there is no energy associated solely // with the first snaxel; energy is based on distance, and there // is no distance associated with a single snaxel. It is only when // we get to the second snaxel, that we have some measure of distance for (int l = 0; l < numNeighbors; l++) { energyMtx[0, l] = 0.0f; posMtx[0, l] = 0; } // Find the average distance between points float distSum = 0.0f; for (int d = 1; d < numPoints; d++) { distSum += (float)MathHelper.GetDistance(contour[d].X, contour[d].Y, contour[d - 1].X, contour[d - 1].Y); } float averageDistance = distSum / numPoints; for (int i = 1; i < numPoints - 1; i++) { for (int j = 0; j < numNeighbors; j++) { // for all neighbors of next node minEnergy = BigFloat; nextNode.X = contour[i + 1].X + neighbor[j].X; nextNode.Y = contour[i + 1].Y + neighbor[j].Y; for (int k = 0; k < numNeighbors; k++) { // for all neighors of curr node currNode.X = contour[i].X + neighbor[k].X; currNode.Y = contour[i].Y + neighbor[k].Y; energy = energyMtx[i - 1, k] + EnergyCalc( edgeImage, energyWeights, contour[i - 1].X + neighbor[posMtx[i - 1, k]].X, contour[i - 1].Y + neighbor[posMtx[i - 1, k]].Y, currNode.X, currNode.Y, nextNode.X, nextNode.Y, averageDistance ); if (energy < minEnergy) { minEnergy = energy; minPosition = k; } } // Store minimum energy into table matrix energyMtx[i, j] = minEnergy; posMtx[i, j] = minPosition; } } int pos = posMtx[numPoints - 2, 4]; // search backwards through table to find optimum positions for (int k = numPoints - 2; k > 0; k--) { contour[k] = new Darwin.Point(contour[k].X + neighbor[pos].X, contour[k].Y + neighbor[pos].Y); pos = posMtx[k - 1, pos]; } return(true); }
/* TODO: References spots in old code * The main algorithm to extract a fin outline from an image. * This method is called from all of this class's constructors, which are called in * TraceWindow.cxx (on_traceButtonImageOK_clicked). * * There are 9 stages: * * 1) Construct, analyize histogram * 2) Threshold GrayImage to create BinaryImage * 3) Clean up / get a cleanner edge through morphological processes * a) open (erode, dialate) * b) erosion with high coefficient to clean up noise, but leave the fin intact * c) AND with the orginal BinaryImage (#3) to restore the fin shape * 4) Feature recognition to select the largest Feature / blob * 5) Get a one pixel outline through one erosion and XORing with #4 * 6) Feature recognition to slect the largest outline (feature /blob) (same code as #4) * 7) Find the start point * A valid start point (p1) must be in math quadrant III * and be followed by two points (p2,p3) * such that p1.row>p2.row>p3.row && p1.col<p2.col<p3.col * 8) Walk the outline from the starting point, recording a pixel in the contour every 3 pixels * 9) Walk ends when no more black pixels may be found. The outline is recouresed backwards until * a valid end point (p1) is found. A valid end point must be in math quadrant IV * and be prefaced by two points (p2,p3) such that p1.row>p2.row>p3.row && p1.col>p2.col>p3.col * * The Contour represented by this object has a length of 0 if at anytime the algorithm * cannot continue. This often occurs for images of poor contrast. * * The Contour represented by this object is adjusted with the snake code in TraceWindow.cxx * if its length is greater than 0. * */ public Contour GetPointsFromBitmap(ref DirectBitmap bmp, Contour ctour, int left, int top, int right, int bottom) { // Resample the image to lower resolution int width = right - left; int factor = 1; while (width / (float)factor > 1024) { //***1.96 - changed magic num JHS factor *= 2; } DirectBitmap workingBmp; if (factor > 1) { workingBmp = DirectBitmapHelper.ResizePercentageNearestNeighbor(bmp, 100.0f / factor); } else { workingBmp = new DirectBitmap(bmp.Bitmap); } int xoffset; int yoffset; workingBmp = DirectBitmapHelper.ApplyBounds(workingBmp, left, top, right, bottom, factor, out xoffset, out yoffset); IntensityHistogram histogram = new IntensityHistogram(workingBmp); Range lowestRange = histogram.FindNextValley(0); Range nextRange = histogram.FindNextValley(lowestRange.End); int totalPixels = workingBmp.Width * workingBmp.Height; // TODO: Magic numbers? if (nextRange.Tip - lowestRange.End < 25 && nextRange.HighestValue > totalPixels / 256) { lowestRange.End = nextRange.End; //TODO: update other values in strut as needed } // TODO: Magic numbers? // low contrast check if (lowestRange.PixelCount > totalPixels * .7 || lowestRange.End > 150 || lowestRange.PixelCount < totalPixels * .2) { //exceeds 90% of images //cout << "Low Contrast Warning..." << endl; //TODO: Do something } // use the range to threshold DirectBitmapHelper.ThresholdRange(ref workingBmp, lowestRange); DirectBitmap saveBinaryBmp = new DirectBitmap(workingBmp.Bitmap); /* ---------------------------------------------------- * Open the image (erode and dilate) * ---------------------------------------------------- */ int iterations = 4; // Default number of iterations int ecount = 0; int itcount = 0; int i; for (i = 0; i < iterations; i++) { ecount = MorphologicalOperators.Erode(ref workingBmp, i % 2); } // Shrink all other regions with less than 5 neighbor black pixles while (ecount != 0) { ecount = MorphologicalOperators.Erode(ref workingBmp, 5); itcount++; } for (i = 0; i < iterations; i++) { MorphologicalOperators.Dilate(ref workingBmp, i % 2); } ; // AND opended image with orginal MorphologicalOperators.And(ref workingBmp, saveBinaryBmp); //Trace.WriteLine("Starting feature recognition..."); var largestFeature = FeatureIdentification.FindLargestFeature(workingBmp); Trace.WriteLine("Feature recognition complete."); // now binImg can be reset to the mask of the NEW largestFeature DirectBitmap binaryBmp = largestFeature.Mask; DirectBitmap outline = new DirectBitmap(binaryBmp.Bitmap); for (i = 0; i < 1; i++) { MorphologicalOperators.Erode(ref outline, 0); } MorphologicalOperators.Xor(ref binaryBmp, outline); //***1.0LK - a bit of a mess - JHS // at this point binImg points to the largestFeature->mask (eroded and XORed). // We want to use this binImg to find a new largestFeature, but we cannot // delete the current largestFeature until after the call to binImg->getLargestFeature() // because binImg will be wiped out by the deletion of the current largestFeature // We must delete the current largestFeature at some point OTHEWISE we have a // memory leak. //get rid of outlines of inner features (e.g. glare spots) by selecting largest outline //cout << "Looking for 2nd Fin Candidate: "; //Feature oldLargest = largestFeature; //***1.0LK var finalLargestFeature = FeatureIdentification.FindLargestFeature(binaryBmp); if (finalLargestFeature == null) { // TODO Trace.WriteLine("largestFeature NULL, aborting. No fin outline determined"); return(null); } // now binImg can be reset to the mask of the NEW largestFeature DirectBitmap finalWorkingBmp = finalLargestFeature.Mask; int row = 0, col = 0; int rows = finalWorkingBmp.Height, cols = finalWorkingBmp.Width; bool done = false; width = 15; //cout << "Finding first point..." << endl; Darwin.Point pt = ctour[0]; //Contour::addPoint(pt.x,pt.y);//Add User start int stx = pt.X / factor - xoffset; int sty = pt.Y / factor - yoffset; pt = ctour[1]; int endy = pt.Y / factor - yoffset; int endx = pt.X / factor - xoffset; //find starting point (midx,midy) int midx; int midy = 0; int maxy = (sty > endy) ? sty : endy; // Math.max(sty,endy); midx = Convert.ToInt32((endx + stx) * .5); //find black pixel closest to bottom in column midx row = maxy; while (!done && row >= 0) { if (finalWorkingBmp.GetPixel(midx, row).GetIntensity() == 0) { midy = row; done = true; } else { row--; } } if (!done) { Trace.WriteLine("no starting point found."); Trace.WriteLine("\nNo outline intersected the bisector of the secant line formed by user supplied start and end points!\n"); // TODO return(null); } Trace.WriteLine(string.Format("Have starting point ({0}, {1})", midx, midy)); Trace.WriteLine(string.Format("FYI ending point ({0}, {1})", endy, endx)); row = midy; col = midx; int st2y = row; int st2x = col; // Walk from point (row,col) finalWorkingBmp.SetPixel(col, row, Color1); /* Prioritize direction of movement * * 4 | 3 | 2 * -- -- -- * 5 | * | 1 * -- -- -- * 4 | 3 | 2 */ i = 0; bool foundPoint = true; bool prepend = false; done = false; while (!done) { /* Prioritize direction of movement * * 4 | 3 | 2 * -- -- -- * 5 | * | 1 * -- -- -- * 4 | 3 | 2 */ if (col + 1 < cols && finalWorkingBmp.GetPixel(col + 1, row).GetIntensity() == 0) {//E foundPoint = true; col = col + 1; } else if (row - 1 >= 0 && finalWorkingBmp.GetPixel(col, row - 1).GetIntensity() == 0) {//N foundPoint = true; row = row - 1; } else if (row + 1 < rows && finalWorkingBmp.GetPixel(col, row + 1).GetIntensity() == 0) {//S foundPoint = true; row = row + 1; } else if (col - 1 >= 0 && finalWorkingBmp.GetPixel(col - 1, row).GetIntensity() == 0) {//W foundPoint = true; col = col - 1; } else { if (prepend) { done = true; break; } else { prepend = true; row = midy; col = midx; continue; } } if (foundPoint /*&& i%3==0*/) { if (prepend) { AddPoint(factor * (col + xoffset), factor * (row + yoffset), 0);//prepend } else { AddPoint(factor * (col + xoffset), factor * (row + yoffset)); } finalWorkingBmp.SetPixel(col, row, Color128); if (row == maxy) { //done with this direction if (prepend) { done = true; break; } else { prepend = true; row = midy; col = midx; continue; } } } i++; } // end loop until done TrimAndReorder(ctour[0], ctour[1]); Trace.WriteLine("IntensityContour::GetPointsFromBitmap COMPLETE"); return(null); }