using System; using HalconDotNet; namespace HalconTools { /// /// This model data class holds general information about a measure /// object. To define more specialized measure data objects the /// classes MeasurementEdge and MeasurementPair are derived from this /// class to be able to distinguish the measure /// types and results for simple edges and for edge pairs. The base /// class contains the methods to create measure handles and to create /// the display results of a measure action. The derived classes /// implement the specialized methods to perform a measure operation /// and generate the measure results. /// public class Measurement { /// HALCON measure object (handle). protected HMeasure mHandle; /// /// Flag to distinguish between a linear and circular measure object. /// protected int mROIType; /// /// Model coordinates obtained from the ROI instance. /// This coordinates are the base to calculate the measuring field. /// protected HTuple mROICoord; /// Reference to the ROI. protected ROI mRoi; /// /// Auxiliary information about the /// measuring field calculated using the ROI coordinates. /// protected HTuple mMeasROI; /// Iconic object to display measure edge results. protected HXLDCont mEdgeXLD; /// Iconic object to display mMeasROI. protected HRegion mMeasureRegion; /// /// Reference to controller class to obtain information about /// the context of the measurement, e.g. image, parameter setups etc. /// protected MeasureAssistant mMeasAssist; /// /// Creates and initializes a measure object based on information the ROI object /// about the ROI. /// /// ROI instance /// Reference to controller class public Measurement(ROI roi, MeasureAssistant mAssist) { mRoi = roi; mMeasAssist = mAssist; mROICoord = mRoi.getModelData(); mEdgeXLD = new HXLDCont(); mMeasureRegion = new HRegion(); if (mRoi is ROICircularArc) mROIType = ROI.ROI_TYPE_CIRCLEARC; else mROIType = ROI.ROI_TYPE_LINE; } /// /// Triggers an update of the measure object for all /// changes concerning the shape of the ROI or the measurement /// parameters. /// public void UpdateROI() { mROICoord = mRoi.getModelData(); UpdateMeasure(); } /// /// Creates a measure object based on the model data /// defined by the ROI instance and the parameters /// describing the measure context. /// protected void UpdateMeasure() { double extent, sPhi, radius; if (mHandle != null) mHandle.Dispose(); mMeasAssist.exceptionText = ""; try { switch (mROIType) { case ROI.ROI_TYPE_CIRCLEARC: radius = mROICoord[2].D; sPhi = mROICoord[3].D; extent = mROICoord[4].D; mMeasROI = GenSurCircle(mROICoord, mMeasAssist.mRoiWidth); mHandle = new HMeasure(mROICoord[0].D, mROICoord[1].D, radius, sPhi, extent, mMeasAssist.mRoiWidth, mMeasAssist.mWidth, mMeasAssist.mHeight, mMeasAssist.mInterpolation); break; case ROI.ROI_TYPE_LINE: mMeasROI = GenSurRect2(mROICoord, mMeasAssist.mRoiWidth); mHandle = new HMeasure(mMeasROI[0].D, mMeasROI[1].D, mMeasROI[2].D, mMeasROI[3].D, mMeasROI[4].D, mMeasAssist.mWidth, mMeasAssist.mHeight, mMeasAssist.mInterpolation); break; //case ROI.ROI_TYPE_LINE: // mMeasROI = GenSurRect2(mROICoord,mMeasAssist.mRoiHeight, mMeasAssist.mRoiWidth); // mHandle = new HMeasure(mMeasROI[0].D, mMeasROI[1].D, // mMeasROI[2].D, mMeasROI[3].D, mMeasROI[4].D, // mMeasAssist.mWidth, mMeasAssist.mHeight, // mMeasAssist.mInterpolation); break; } } catch (HOperatorException e) { mEdgeXLD.Dispose(); mMeasureRegion.Dispose(); mMeasAssist.exceptionText = e.Message; ClearResultData(); return; } UpdateResults(); UpdateMeasureRegion(); } /// /// Defines the measuring field of a linear ROI. /// /// /// Model data for a linear interactive ROI /// /// Half width of (rectangular) measure ROI /// Model data describing a linear measuring field private HTuple GenSurRect2(HTuple line, double width) { double row1 = line[0]; double col1 = line[1]; double row2 = line[2]; double col2 = line[3]; double phi = HMisc.AngleLx(row1, col1, row2, col2); double length1 = (HMisc.DistancePp(row1, col1, row2, col2)) / 2.0; double length2 = width; double rowM = (row1 + row2) / 2; double colM = (col1 + col2) / 2; return new HTuple(new double[] { rowM, colM, phi, length1, length2 }); } private HTuple GenSurRect2(HTuple line,double height, double width) { double row1 = line[0]; double col1 = line[1]; double row2 = line[2]; double col2 = line[3]; double phi = HMisc.AngleLx(row1, col1, row2, col2); double length1 = height / 2.0; double length2 = width; double rowM = (row1 + row2) / 2; double colM = (col1 + col2) / 2; return new HTuple(new double[] { rowM, colM, phi, length1, length2 }); } /// /// Defines the measuring field of a circular ROI. /// /// /// Model data for a circular ROI /// /// Radius (half width) of the circular (ring-shaped) ROI /// Model data describing circular measuring field private HTuple GenSurCircle(HTuple circle, double width) { double row1 = circle[0]; double col1 = circle[1]; double radius = circle[2]; double startPhi = circle[3]; double extent = circle[4]; if (radius <= width) return new HTuple(new double[] { row1, col1, startPhi, extent, (radius + width), 0.0 }); else return new HTuple(new double[] { row1, col1, startPhi, extent, (radius + width), (radius - width) }); } /// Releases resources used for this measure object. public void ClearMeasurement() { if (mHandle != null) { mHandle.Dispose(); mEdgeXLD.Dispose(); mMeasureRegion.Dispose(); } } /// /// Creates the iconic object for displaying a measured /// edge in a linear ROI. /// /// Contour depicting the measured edge public static HXLDCont DetermineEdgeLine(double row, double col, double phi, double width) { double row1, row2, col1, col2; row1 = row - width * Math.Sin(phi + 0.5 * Math.PI); col1 = col + width * Math.Cos(phi + 0.5 * Math.PI); row2 = row - width * Math.Sin(phi + 1.5 * Math.PI); col2 = col + width * Math.Cos(phi + 1.5 * Math.PI); return DetermineLine(row1, col1, row2, col2); } /// /// Creates the iconic object for displaying a measured /// edge from the coordinates of the end points. /// /// Contour depicting the measured edge public static HXLDCont DetermineLine(double row1, double col1, double row2, double col2) { HXLDCont edge = new HXLDCont(); HTuple rows, cols; rows = new HTuple(new double[] { row1, row2 }); cols = new HTuple(new double[] { col1, col2 }); edge.GenContourPolygonXld(rows, cols); return edge; } /// /// Creates the iconic object for displaying a measured /// edge in a circular ROI. /// /// Edge contour depicting a measured edge public static HXLDCont DetermineEdgeCircularArc(double row, double col, double center_row, double center_col, double radius, double width) { double row1, row2, col1, col2; row1 = row + (center_row - row) / radius * width; col1 = col + (center_col - col) / radius * width; row2 = row - (center_row - row) / radius * width; col2 = col - (center_col - col) / radius * width; return DetermineLine(row1, col1, row2, col2); } /// /// Creates the iconic object for displaying /// the arc between edges of a pair. /// /// Edge contour depicting the arc between edges of a pair public static HXLDCont DeterminePairCircularArc(double row1, double col1, double row2, double col2, double cRow, double cCol, double radius, double width, bool positive) { HXLDCont arc = new HXLDCont(); double startPhi, endPhi; startPhi = Math.Atan2(cRow - row1, col1 - cCol); endPhi = Math.Atan2(cRow - row2, col2 - cCol); arc.GenEllipseContourXld(cRow, cCol, 0.0, radius, radius, startPhi, endPhi, (positive ? "positive" : "negative"), 1.5); return arc; } /// /// Creates an iconic object depicting the /// measuring field. /// public void UpdateMeasureRegion() { mMeasureRegion.Dispose(); mMeasureRegion.GenEmptyObj(); if (mROIType == ROI.ROI_TYPE_CIRCLEARC) { double sPhi, extent, innerRad, outerRad; HTuple innerR, outerR, innerC, outerC; HXLDCont outCont, innerCont, contour; outCont = new HXLDCont(); innerCont = new HXLDCont(); sPhi = mMeasROI[2].D; extent = mMeasROI[3].D; outerRad = mMeasROI[4].D; innerRad = mMeasROI[5].D; innerCont.GenCircleContourXld(mMeasROI[0].D, mMeasROI[1].D, innerRad, sPhi, (sPhi + extent), (extent > 0) ? "positive" : "negative", 1.0); outCont.GenCircleContourXld(mMeasROI[0].D, mMeasROI[1].D, outerRad, (sPhi + extent), sPhi, (extent > 0) ? "negative" : "positive", 1.0); innerCont.GetContourXld(out innerR, out innerC); outCont.GetContourXld(out outerR, out outerC); innerR = innerR.TupleConcat(outerR); innerC = innerC.TupleConcat(outerC); contour = new HXLDCont(innerR, innerC); contour = contour.CloseContoursXld(); mMeasureRegion = contour.GenRegionContourXld("margin"); contour.Dispose(); innerCont.Dispose(); outCont.Dispose(); } else { mMeasureRegion.GenRectangle2(mMeasROI[0].D, mMeasROI[1].D, mMeasROI[2].D, mMeasROI[3].D, mMeasROI[4].D); } } /// /// If calibration data is available and valid, then rectify /// measure result coordinates, otherwise leave them the same /// public void Rectify(HTuple row, HTuple col, out HTuple rowRect, out HTuple colRect) { double unitScale=0.0; if (mMeasAssist.mIsCalibValid) { switch (mMeasAssist.mUnit) { case "µm": unitScale = 0.000001; break; case "mm": unitScale = 0.001; break; case "cm": unitScale = 0.01; break; case "m": unitScale = 1.0; break; default: break; } HOperatorSet.ImagePointsToWorldPlane(mMeasAssist.mCamParameter, mMeasAssist.mCamPose, row, col, new HTuple(unitScale), out colRect, out rowRect); } else { rowRect = row; colRect = col; } } /// /// If calibration data is available and valid, then transform the /// distance between measure result edges into world coordinates, /// else leave them the same. /// public HTuple Distance(HTuple row1, HTuple col1, HTuple row2, HTuple col2, int shift) { HTuple rows, cols, rowRect, colRect; HTuple distance = new HTuple(); HXLDCont contour; if (shift == 0) { if (mROIType == ROI.ROI_TYPE_CIRCLEARC) { double cRow, cCol, radius, extent, phi1, phi2, phi, res, length, tmp; cRow = mROICoord[0].D; cCol = mROICoord[1].D; radius = mROICoord[2].D; extent = mROICoord[4].D; HOperatorSet.TupleGenConst(new HTuple(row1.Length), 0.0, out distance); for (int i=0; i < distance.Length; i++) { phi1 = HMisc.AngleLx(cRow, cCol, row1[i].D, col1[i].D); phi2 = HMisc.AngleLx(cRow, cCol, row2[i].D, col2[i].D); if (extent < 0) { tmp = phi1; phi1 = phi2; phi2 = tmp; } phi = phi2 - phi1; if (phi < 0) phi += 2 * Math.PI; res = 0.05 * 24.0 / (radius * phi); contour = new HXLDCont(); contour.GenEllipseContourXld(cRow, cCol, 0, radius, radius, phi1, phi2, "positive", res); contour.GetContourXld(out rows, out cols); Rectify(rows, cols, out rowRect, out colRect); contour.Dispose(); contour.GenContourPolygonXld(rowRect, colRect); length = contour.LengthXld(); distance[i].D = length; contour.Dispose(); } } else if (mROIType == ROI.ROI_TYPE_LINE) { HTuple rRect1, cRect1, rRect2, cRect2; Rectify(row1, col1, out rRect1, out cRect1); Rectify(row2, col2, out rRect2, out cRect2); distance = HMisc.DistancePp(rRect1, cRect1, rRect2, cRect2); } return distance; } else { HTuple rClip1, cClip1, rShift2, cShift2; rClip1 = row1.TupleSelectRange(new HTuple(0), new HTuple(row1.Length - shift - 1)); cClip1 = col1.TupleSelectRange(new HTuple(0), new HTuple(col1.Length - shift - 1)); rShift2 = row2.TupleSelectRange(new HTuple(shift), new HTuple(row2.Length - 1)); cShift2 = col2.TupleSelectRange(new HTuple(shift), new HTuple(col2.Length - 1)); return this.Distance(rClip1, cClip1, rShift2, cShift2, 0); } } /// /// Returns the iconic object describing the measuring field /// of the measure object. /// public HRegion getMeasureRegion() { return mMeasureRegion; } /// /// Returns the iconic object depicting the measured edges. /// public HXLDCont getMeasureResults() { return mEdgeXLD; } /// /// Returns the gray-value profile obtained by the measure projection /// operation. /// /// Gray-value profile public double[] getGrayValueProj() { HTuple grayVal; if (mHandle == null || (int)mHandle.Handle < 0) return null; grayVal = mHandle.MeasureProjection(mMeasAssist.mImage); return grayVal.ToDArr(); } /********************************************************/ /********************************************************/ /// /// Virtual method to be implemented by the derived classes. /// public virtual void UpdateResults() { } /// /// Virtual method to be implemented by the derived classes. /// public virtual void UpdateXLD() { } /// /// Virtual method to be implemented by the derived classes. /// public virtual void ClearResultData() { } /// /// Virtual method to be implemented by the derived classes. /// public virtual MeasureResult getMeasureResultData() { return null; } }//end of class }//end of namespace