public override bool CheckShape(CalibrationShape shape) { int cx = shape.GravityCenter.X.Round(); int cy = shape.GravityCenter.Y.Round(); int redCount = 0; for(int dx = -_r; dx <= _r; ++dx) { for(int dy= -_r; dy <= _r; ++dy) { redCount = Image[cy + dy, cx + dx, (int)RGBChannel.Red] > _minRed ? redCount + 1 : redCount; } } return redCount > _winSize * 0.75; }
// 1) Move around the border and FF for each 'Unvisited', fill background ( dark ) with 'Background' // 2) During FF mark some white field and now start FF and fill light area with 'WhiteField' // We assume white field is one big connected area ( with 'holes' for calibration shapes ) // 3) If during WF some unvisited dark area is run into, FF it with 'Shape', create CalibrationShape // for it and add its points, save index in pixel codes public override void FindCalibrationPoints() { //if(UseMedianFilter) //{ // // Preprocess with median filter to remove some noise (edges should stay in same place ) // MedianFilter filter = new MedianFilter(); // filter.FilterBorder = false; // filter.Image = Image.ImageMatrix; // filter.WindowRadius = MedianFilterRadius; // ImageGray.ImageMatrix = filter.ApplyFilter(); //} PrimaryShapeChecker.Image = Image; _pixelCodes = new DenseMatrix(Image.RowCount, Image.ColumnCount); CalibShapes = new List<CalibrationShape>(32); _whiteBorder = new List<TPoint2D<int>>(); // Fill whole background first FillBackground(); _currentShape = null; CalibShapes.Add(null); // Reserve slot for primary shape if(_whiteBorder.Count == 0) { // No white field detected -> error MessageBox.Show("No white field detected on calibration image: no calibration points can be found"); return; } // Fill white field and shapes (inside FillWhiteField) FillWhiteField(); if(CalibShapes[0] == null) { MessageBox.Show("No primary calibration shape (reddish) detected on calibration image: no calibration points can be found"); return; } // Now find main white field ( one with primary shape ) and remove all shapes // not from this field uint primaryField = CalibShapes[0].Index; for(int i = 1; i < CalibShapes.Count;) { if(CalibShapes[i].Index != primaryField) { CalibShapes.RemoveAt(i); continue; } ++i; } // At this point CalibrationShapes should be created, so find its centers // and sort them to form grid FillCalibrationGrid(); // From each valid shape from grid, create CalibrationPoint Points = new List<CalibrationPoint>(); foreach(var shape in CalibGrid) { if(shape != null && !shape.IsInvalid) Points.Add(new CalibrationPoint() { Img = shape.GravityCenter, RealGridPos = shape.GridPos }); } ((ShapeGridLinesExtractor)LinesExtractor).CalibGrid = CalibGrid; }
private void FindLocalAxes(out CalibrationShape shapeX, out CalibrationShape shapeY) { // Find calibration grid axes // 1) Sort shapes by distance to primary shape CalibShapes.Sort((s1, s2) => { // Compares distance of s1 and s2 to primary shape return (s1.GravityCenter - CalibShapes[0].GravityCenter).LengthSquared().CompareTo( (s2.GravityCenter - CalibShapes[0].GravityCenter).LengthSquared()); }); // 2) Find direction vectors from PS to closest one and then find // closest one with direction rotated by 90deg ( by comparing its dot product -> // for 90deg its 0, having like 10deg tolerance we have : // dot(A,B) / (|A||B|) = cos(a) < 0.17 // Use 2 next closest ones shapeX = null; shapeY = null; Vector2 direction_1 = (CalibShapes[1].GravityCenter - CalibShapes[0].GravityCenter); direction_1.Normalise(); shapeX = CalibShapes[1]; //Vector2 direction_2 = direction_1; //int pointNum = 2; //for(; pointNum < CalibShapes.Count; ++pointNum) //{ // // Find direction and dot product // direction_2 = (CalibShapes[pointNum].GravityCenter - CalibShapes[0].GravityCenter); // direction_2.Normalise(); // if(Math.Abs(direction_1.CosinusTo(direction_2)) < 0.17) // { // // Found prependicular direction // shapeY = CalibShapes[pointNum]; // break; // } //} Vector2 direction_2 = (CalibShapes[2].GravityCenter - CalibShapes[0].GravityCenter); direction_2.Normalise(); double cos2 = Math.Abs(direction_1.CosinusTo(direction_2)); Vector2 direction_3 = (CalibShapes[3].GravityCenter - CalibShapes[0].GravityCenter); direction_3.Normalise(); double cos3 = Math.Abs(direction_1.CosinusTo(direction_3)); // Choose one with angle closer to 90deg (so cos closer to 0) direction_2 = cos2 < cos3 ? direction_2 : direction_3; shapeY = cos2 < cos3 ? CalibShapes[2] : CalibShapes[3]; // Now depending on sign of sin(a), we can determine which axis is X and Y // Using cross-product of d1 and d2 ( casting it to 3d with z = 0 ) we have sin(a) = (d1.x * d2.y - d1.y * d2.x) // If sin(a) > 0, then d1 is local x axis, d2 is y if(direction_1.SinusTo(direction_2) > 0.0) { AxisX = direction_1; AxisY = direction_2; } else { AxisX = direction_2; AxisY = direction_1; var temp = shapeY; shapeY = shapeX; shapeX = temp; } }
private void InitCalibrationGrid(CalibrationShape shapeX, CalibrationShape shapeY) { CalibGrid = new CalibrationGrid(4, 4); CalibGrid.Add(0, 0, CalibShapes[0]); CalibShapes.RemoveAt(0); CalibGrid.Add(0, 1, shapeX); CalibShapes.Remove(shapeX); CalibGrid.Add(1, 0, shapeY); CalibShapes.Remove(shapeY); }
private void AddDummyShape(int x, int y, Vector2 eP) { CalibrationShape dummy = new CalibrationShape(); dummy.GravityCenter = eP; dummy.IsInvalid = true; CalibGrid.Add(y, x, dummy); }
void FillShape(int y, int x) { _flood = new IterativeBasicFloodAlgorithm(); _flood.ImageHeight = Image.RowCount; _flood.ImageWidth = Image.ColumnCount; _flood.FillCondition = ShapeFillCondition; _flood.FillAction = ShapeFillAction; // Create new CalibrationShape and set index in pixelcodes _currentShape = new CalibrationShape(); _currentShape.Index = (uint)_currentWhiteField; _pixelCodes[y, x] = CellCodeToFloat(CellCode.Unvisited); _flood.FloodFill(y, x); _currentShape.FindCenter(); // Check if its primary shape -> should have very high red value if(PrimaryShapeChecker.CheckShape(_currentShape)) { CalibShapes[0] = _currentShape; } else { CalibShapes.Add(_currentShape); } }
public abstract bool CheckShape(CalibrationShape shape);