/// <summary> /// Constructs a new circle provider with /// default properties /// </summary> public CircleProvider() { Color = FColor.Black; Center = new IppiPoint_32f(0, 0); Radius = 1; SegmentCount = 72; }
/// <summary> /// Constructs a new circle provider /// </summary> /// <param name="color">The (fill) color of the circle</param> /// <param name="center">The circles center in device coordinates</param> /// <param name="radius">The circles radius in device units</param> /// <param name="segmentCount">The number of segments to draw - more=smoother circle</param> public CircleProvider(FColor color, IppiPoint_32f center, float radius, ushort segmentCount) { Color = color; Center = center; Radius = radius; SegmentCount = segmentCount; }
public PointAnalysis(IppiPoint coordinate, IppiPoint_32f smoothenedCoordinate, float instantSpeed) { CompletedBout = null; OriginalCoordinate = coordinate; SmoothenedCoordinate = smoothenedCoordinate; InstantSpeed = instantSpeed; }
public void Precompute() { if (!Complete) { throw new InvalidOperationException("Can't precompute lookup table before completing calibration"); } if (Precomputed) { return; } //create new tables _preCompX = new float[_scanRoi.Width * _scanRoi.Height]; _preCompY = new float[_scanRoi.Width * _scanRoi.Height]; //iterate over each coordinate within the image borders //and precompute it's voltages, storing it in the table for (int x = 0; x < _scanRoi.Width; x++) { for (int y = 0; y < _scanRoi.Height; y++) { IppiPoint_32f voltages = this[new IppiPoint(x + _scanRoi.X, y + _scanRoi.Y)]; _preCompX[y * _scanRoi.Width + x] = voltages.x; _preCompY[y * _scanRoi.Width + x] = voltages.y; } } Precomputed = true; }
/// <summary> /// Constructs a new linear gradient provider /// </summary> /// <param name="topleft">The topleft corner of the gradient rectangle</param> /// <param name="width">The width of the gradient rectangle</param> /// <param name="height">The height of the gradient rectangle</param> /// <param name="colStart">The starting color of the gradient</param> /// <param name="colEnd">The ending color of the gradient</param> public LinGradientProvider(IppiPoint_32f topleft, float width, float height, FColor colStart, FColor colEnd) { Topleft = topleft; Width = width; Height = height; ColStart = colStart; ColEnd = colEnd; }
/// <summary> /// Constructs a new quad with the specified corners and color /// corners should be indicated in clock-wise direction /// </summary> /// <param name="corner1"></param> /// <param name="corner2"></param> /// <param name="corner3"></param> /// <param name="corner4"></param> /// <param name="color"></param> public Quad(IppiPoint_32f corner1, IppiPoint_32f corner2, IppiPoint_32f corner3, IppiPoint_32f corner4, FColor color) { Corner1 = corner1; Corner2 = corner2; Corner3 = corner3; Corner4 = corner4; Color = color; }
/// <summary> /// Default constructor /// </summary> public Quad() { Corner1 = new IppiPoint_32f(); Corner2 = new IppiPoint_32f(); Corner3 = new IppiPoint_32f(); Corner4 = new IppiPoint_32f(); Color = FColor.Black; }
/// <summary> /// Default constructor /// </summary> public LinGradientProvider() { Topleft = new IppiPoint_32f(-8, -8); Width = 16; Height = 12; ColStart = FColor.Black; ColEnd = FColor.White; }
/// <summary> /// Creates a new Luminance neutral circle provider /// </summary> /// <param name="foreground">The color of the foreground checkers</param> /// <param name="checkerWidth">The width of the checkers</param> /// <param name="checkerHeight">The height of the checkers</param> /// <param name="center">The center of the circle</param> /// <param name="radius">The radius of the circle</param> public LumNeutralCircleProvider(FColor foreground, float checkerWidth, float checkerHeight, IppiPoint_32f center, float radius) { Foreground = foreground; CheckerWidth = checkerWidth; CheckerHeight = checkerHeight; Center = center; Radius = radius; SegmentCount = 72; }
/// <summary> /// Creates a new Luminance neutral circle provider /// </summary> public LumNeutralCircleProvider() { Foreground = FColor.Red; CheckerWidth = 0.1f; CheckerHeight = 0.1f; Center = new IppiPoint_32f(0, 0); Radius = 1; SegmentCount = 72; }
/// <summary> /// Creates a new Y-Maze provider. The coordinates are intended to follow each other in clock-wise direction starting at the meeting point /// of bottom arm and left arm /// </summary> public YMazeProvider(IppiPoint_32f p1, IppiPoint_32f p2, IppiPoint_32f p3, IppiPoint_32f p4, IppiPoint_32f p5, IppiPoint_32f p6, IppiPoint_32f p7, IppiPoint_32f p8, IppiPoint_32f p9, FColor arm1, FColor arm2, FColor arm3) { _arm1 = new Quad(p1, p2, p3, p4, arm1); _arm2 = new Quad(p4, p5, p6, p7, arm2); _arm3 = new Quad(p7, p8, p9, p1, arm3); _vertex13 = new FColor((arm1.R + arm3.R) / 2, (arm1.G + arm3.G) / 2, (arm1.B + arm3.B) / 2); _vertex21 = new FColor((arm1.R + arm2.R) / 2, (arm1.G + arm2.G) / 2, (arm1.B + arm2.B) / 2); _vertex32 = new FColor((arm2.R + arm3.R) / 2, (arm2.G + arm3.G) / 2, (arm2.B + arm3.B) / 2); }
/// <summary> /// Populates a drawing provider from a string representation /// </summary> /// <param name="s">The string representation</param> public override void FromFileString(string s) { string[] parts = s.Split(';'); if (parts.Length != 8 || parts[0] != "Circle") { throw new ApplicationException("Provided string does not represent a CircleProvider"); } Color = new FColor(float.Parse(parts[1]), float.Parse(parts[2]), float.Parse(parts[3])); Radius = float.Parse(parts[4]); Center = new IppiPoint_32f(float.Parse(parts[5]), float.Parse(parts[6])); SegmentCount = ushort.Parse(parts[7]); }
public override void FromFileString(string s) { string[] parts = s.Split(';'); if (parts.Length != 11 || parts[0] != "LinGrad") { throw new ApplicationException("Provided string does not represent a FourSquareProvider"); } Topleft = new IppiPoint_32f(float.Parse(parts[1]), float.Parse(parts[2])); Width = float.Parse(parts[3]); Height = float.Parse(parts[4]); ColStart = new FColor(float.Parse(parts[5]), float.Parse(parts[6]), float.Parse(parts[7])); ColEnd = new FColor(float.Parse(parts[8]), float.Parse(parts[9]), float.Parse(parts[10])); }
public override IppiPoint_32f this[IppiPoint p] { get { if (p.x >= _imageWidth || p.x < 0 || p.y >= _imageHeight || p.y < 0) { throw new ArgumentOutOfRangeException("Requested coordinate is outside of the calibrated image dimensions"); } if (!Complete) { throw new NotSupportedException("Can't obtain voltages before calibration"); } IppiPoint_32f retval = new IppiPoint_32f(_xVolts[p.x], _yVolts[p.y]); return(retval); } }
/// <summary> /// Method to perform all necessary steps to find one calibration point /// in three-point calibration /// </summary> /// <param name="frame">Frame number 0-based from start of operation</param> /// <param name="camImage">The current camera image</param> /// <param name="voltages">The voltages to move laser to</param> /// <returns>-1,-1 or the identified point</returns> protected IppiPoint MoveAndDetect(int frame, Image8 camImage, IppiPoint_32f voltages) { if (frame < Properties.Settings.Default.FrameRate / 10) { //In the first 100 ms we just give the scanner ample time to reach the target _scanner.Hit(voltages); return(new IppiPoint(-1, -1)); } else if (frame < Properties.Settings.Default.FrameRate * 1.1) { //In the next second we build our foreground _laser.LaserPower = Properties.Settings.Default.LaserCalibPowermW; _fgModel.UpdateBackground(camImage); return(new IppiPoint(-1, -1)); } else { //Let's find the beam location and return it return(FindBeamLocation(_fgModel.Background, _bgModel.Background, _calc, _foreground)); } }
/// <summary> /// Rotates the mirrors according to given voltages /// </summary> /// <param name="voltages">The x/y voltages to apply to the servo controllers</param> /// <returns>The status code of the targeting attempt</returns> public HitStatus Hit(IppiPoint_32f voltages) { if (voltages.x < VMin || voltages.y < VMin || voltages.x > VMax || voltages.y > VMax) { return(HitStatus.OutOfRange); } try { //_xWriter.WriteSingleSample(true, voltages.x); //_yWriter.WriteSingleSample(true, voltages.y); double[] volts = new double[2]; volts[0] = voltages.x; volts[1] = voltages.y; _multiWriter.WriteSingleSample(true, volts); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e); return(HitStatus.Exception); } return(HitStatus.Success); }
/// <summary> /// Tests the connection with the mirror setup reading position /// values back from the indicated analog in channels on the indicated device /// </summary> /// <param name="aiDevice">The NI board to connect to (f.e. "dev1")</param> /// <param name="aiX">The analog in that reads x-mirror position (f.e. "ai0")</param> /// <param name="aiY">The analog in that reads y-mirror position (f.e. "ai1")</param> /// <param name="scaleFactor">The scale factor between supplied ao-voltage and the corresponding ai-voltage supplied by the breakout board (scale = V(ai)/V(a0))</param> /// <returns>True if successfull</returns> public bool TestConnection(string aiDevice, string aiX, string aiY, double scaleFactor) { string connectX = aiDevice + '/' + aiX; string connectY = aiDevice + '/' + aiY; Task mirrorPosTask = new Task("mirrorRead"); var samples = new double[2, 100]; //in each read we read 10 samples from 2 analog ins (mirrorX and mirrorY) double avgx, avgy; //the averages of the read voltages for both mirrors mirrorPosTask.AIChannels.CreateVoltageChannel(connectX, "ChanXMirror", AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts); mirrorPosTask.AIChannels.CreateVoltageChannel(connectY, "ChanYMirror", AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts); mirrorPosTask.Timing.ConfigureSampleClock("", 100, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, 100); AnalogMultiChannelReader aiReader = new AnalogMultiChannelReader(mirrorPosTask.Stream); //hit first point IppiPoint_32f target = new IppiPoint_32f(-5, -5); Hit(target); System.Threading.Thread.Sleep(10);//give mirrors time to settle mirrorPosTask.Start(); while (mirrorPosTask.Stream.AvailableSamplesPerChannel < 100) { } //wait until all samples are acquired //read mirror position back samples = aiReader.ReadMultiSample(100); mirrorPosTask.Stop(); avgx = avgy = 0; for (int i = 0; i < 100; i++) { avgx += (samples[0, i] / 100); avgy += (samples[1, i] / 100); } if (Math.Round(avgx / scaleFactor) != -5 || Math.Round(avgy / scaleFactor) != -5) { mirrorPosTask.Dispose(); return(false); } //hit second point target.x = 5; target.y = 5; Hit(target); System.Threading.Thread.Sleep(10);//give mirrors time to settle mirrorPosTask.Start(); while (mirrorPosTask.Stream.AvailableSamplesPerChannel < 100) { } //wait until all samples are acquired //read mirror position back samples = aiReader.ReadMultiSample(100); mirrorPosTask.Stop(); avgx = avgy = 0; for (int i = 0; i < 100; i++) { avgx += (samples[0, i] / 100); avgy += (samples[1, i] / 100); } if (Math.Round(avgx / scaleFactor) != 5 || Math.Round(avgy / scaleFactor) != 5) { mirrorPosTask.Dispose(); return(false); } mirrorPosTask.Dispose(); return(true); }
/* * /// <summary> * /// The width of the border within which we calibrated * /// </summary> * public int Border * { * get * { * return _border; * } * } */ /// <summary> /// For a given point returns the corresponding /// x and y voltages /// </summary> /// <param name="p">The coordinate to look up</param> /// <returns>A 2 element array containing the x-voltage and y-voltage</returns> public override IppiPoint_32f this[IppiPoint p] { get { if (!_complete) { throw new InvalidOperationException("Tried to use non-complete calibration table"); } IppiPoint_32f retval = new IppiPoint_32f(); if (p.x < _scanRoi.X || p.x >= (_scanRoi.Width + _scanRoi.X)) { throw new ArgumentOutOfRangeException("X coordinate outside lookup table area"); } if (p.y < _scanRoi.Y || p.y >= (_scanRoi.Height + _scanRoi.Y)) { throw new ArgumentOutOfRangeException("Y coordinate outside lookup table area"); } if (Precomputed) { //our precomputed lookup table has a size equal to the ROI size //therefore we need to deduct the ROI start from the point //coordinates p.x = p.x - _scanRoi.X; p.y = p.y - _scanRoi.Y; retval.x = _preCompX[p.y * _scanRoi.Width + p.x]; retval.y = _preCompY[p.y * _scanRoi.Width + p.x]; return(retval); } int xIn, yIn; //correct for the border presence xIn = p.x - _scanRoi.X; yIn = p.y - _scanRoi.Y; //find table coordinates of the closest points with LOWER coordinates //then the other borders will be +1 from that int xTabLeft, yTabTop, xTabRight, yTabBottom; xTabLeft = xIn / _spacing; yTabTop = yIn / _spacing; xTabRight = xTabLeft + 1; yTabBottom = yTabTop + 1; if (xTabLeft * _spacing == xIn && yTabTop * _spacing == yIn) { //we don't need to interpolate retval.x = _xVolts[yTabTop * _c + xTabLeft]; retval.y = _yVolts[yTabTop * _c + xTabLeft]; return(retval); } else if (xTabLeft * _spacing == xIn) { //we only need to interpolate along y int ydist = yIn - yTabTop * _spacing; //the larger the distance, the more we weigh in the value from the bottom point float bottomFrac = (float)ydist / (float)_spacing; retval.x = _xVolts[yTabTop * _c + xTabLeft] * (1 - bottomFrac) + _xVolts[yTabBottom * _c + xTabLeft] * bottomFrac; retval.y = _yVolts[yTabTop * _c + xTabLeft] * (1 - bottomFrac) + _yVolts[yTabBottom * _c + xTabLeft] * bottomFrac; return(retval); } else if (yTabTop * _spacing == yIn) { //we only need to interpolate along x int xdist = xIn - xTabLeft * _spacing; //the larger the distance the more we weigh in the value from the right point float rightFrac = (float)xdist / (float)_spacing; retval.x = _xVolts[yTabTop * _c + xTabLeft] * (1 - rightFrac) + _xVolts[yTabTop * _c + xTabRight] * rightFrac; retval.y = _yVolts[yTabTop * _c + xTabLeft] * (1 - rightFrac) + _yVolts[yTabTop * _c + xTabRight] * rightFrac; return(retval); } else { //bilinear interpolation float[] top, bottom; top = new float[2]; bottom = new float[2]; int xdist = xIn - xTabLeft * _spacing; //the larger the distance the more we weigh in the value from the right point float rightFrac = (float)xdist / (float)_spacing; int ydist = yIn - yTabTop * _spacing; //the larger the distance, the more we weigh in the value from the bottom point float bottomFrac = (float)ydist / (float)_spacing; //first we interpolate along x for both top and bottom top[0] = _xVolts[yTabTop * _c + xTabLeft] * (1 - rightFrac) + _xVolts[yTabTop * _c + xTabRight] * rightFrac; top[1] = _yVolts[yTabTop * _c + xTabLeft] * (1 - rightFrac) + _yVolts[yTabTop * _c + xTabRight] * rightFrac; bottom[0] = _xVolts[yTabBottom * _c + xTabLeft] * (1 - rightFrac) + _xVolts[yTabBottom * _c + xTabRight] * rightFrac; bottom[1] = _yVolts[yTabBottom * _c + xTabLeft] * (1 - rightFrac) + _yVolts[yTabBottom * _c + xTabRight] * rightFrac; //now we interpolate between top and bottom retval.x = top[0] * (1 - bottomFrac) + bottom[0] * bottomFrac; retval.y = top[1] * (1 - bottomFrac) + bottom[1] * bottomFrac; return(retval); } } }
/// <summary> /// Computes the Euclidian distance between two points /// </summary> /// <param name="p1">Point1</param> /// <param name="p2">Point2</param> /// <returns>The euclidian distance</returns> public static double Euclidian(IppiPoint_32f p1, IppiPoint_32f p2) { return(Math.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))); }