using System; using System.Collections.Generic; using System.Linq; using System.Text; using HalconDotNet; namespace HalconTools { public class QualityProcedures { /// /// Evaluates the sharpness of the calibration plate in the calibration /// image. /// public void eval_caltab_focus(HObject ho_Image, HObject ho_Marks, HTuple hv_Contrast, out HTuple hv_FocusScore) { // Local iconic variables HObject ho_Region, ho_RegionUnion, ho_ImageReduced; HObject ho_DerivGauss; // Local control variables HTuple hv_Number, hv_MeanGradient, hv_Deviation; HTuple hv_MinScore, hv_RawResult; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Region); HOperatorSet.GenEmptyObj(out ho_RegionUnion); HOperatorSet.GenEmptyObj(out ho_ImageReduced); HOperatorSet.GenEmptyObj(out ho_DerivGauss); hv_FocusScore = 0.0; if ((int)(new HTuple(hv_Contrast.TupleEqual(0))) != 0) { ho_Region.Dispose(); ho_RegionUnion.Dispose(); ho_ImageReduced.Dispose(); ho_DerivGauss.Dispose(); return; } HOperatorSet.CountObj(ho_Marks, out hv_Number); if ((int)(new HTuple(hv_Number.TupleLess(3))) != 0) { ho_Region.Dispose(); ho_RegionUnion.Dispose(); ho_ImageReduced.Dispose(); ho_DerivGauss.Dispose(); return; } ho_Region.Dispose(); HOperatorSet.GenRegionContourXld(ho_Marks, out ho_Region, "margin"); ho_RegionUnion.Dispose(); HOperatorSet.Union1(ho_Region, out ho_RegionUnion); ho_ImageReduced.Dispose(); HOperatorSet.ReduceDomain(ho_Image, ho_RegionUnion, out ho_ImageReduced); ho_DerivGauss.Dispose(); HOperatorSet.DerivateGauss(ho_ImageReduced, out ho_DerivGauss, 0.7, "gradient"); HOperatorSet.Intensity(ho_Region, ho_DerivGauss, out hv_MeanGradient, out hv_Deviation); hv_MinScore = 0.25; //Normalize the Gradient with the contrast hv_RawResult = hv_MeanGradient / hv_Contrast; hv_FocusScore = (((hv_RawResult * 4.5)).TupleSort())[(new HTuple((new HTuple(hv_RawResult.TupleLength() )) / 20.0)).TupleRound()]; hv_FocusScore = ((((((((hv_FocusScore - hv_MinScore)).TupleConcat(0.0))).TupleMax() )).TupleConcat(1.0))).TupleMin(); ho_Region.Dispose(); ho_RegionUnion.Dispose(); ho_ImageReduced.Dispose(); ho_DerivGauss.Dispose(); return; } /// /// Extracts the calibration plate and the marks on this plate /// for the supplied image /// public void find_caltab_edges(HObject ho_Image, out HObject ho_Caltab, out HObject ho_Marks, HTuple hv_DescriptionFileName) { // Stack for temporary objects HObject[] OTemp = new HObject[20]; // Local iconic variables HObject ho_ImageMean, ho_RegionDynThresh, ho_RegionBorder; HObject ho_RegionOpening1, ho_ConnectedRegions1, ho_SelectedRegions4; HObject ho_SelectedRegions5, ho_RegionBorder2, ho_RegionTrans; HObject ho_RegionErosion, ho_RegionBorder1, ho_RegionDilation2; HObject ho_RegionDifference1, ho_RegionOpening, ho_ConnectedRegions; HObject ho_SelectedRegions2, ho_SelectedRegions, ho_RegionFillUp; HObject ho_SelectedRegions1, ho_RegionIntersection, ho_RegionFillUp1; HObject ho_RegionDifference, ho_CaltabCandidates, ho_ObjectSelected = null; HObject ho_ConnectedMarks = null, ho_ObjectSelectedCaltab = null; HObject ho_RegionFillUpCand, ho_MarksCand, ho_RegionDilation1; HObject ho_ImageReduced, ho_DefaultEdges, ho_UnionContours; HObject ho_SelectedXLD, ho_SelectedXLD1; // Local control variables HTuple hv_Width, hv_Height, hv_EstimatedCaltabSize; HTuple hv_EstimatedMarkSize, hv_Number, hv_X, hv_Y, hv_Z; HTuple hv_NumDescrMarks, hv_Index, hv_NumberMarks = new HTuple(); HTuple hv_Anisometry = new HTuple(), hv_Bulkiness = new HTuple(); HTuple hv_StructureFactor = new HTuple(), hv_AreaMarks = new HTuple(); HTuple hv_Row = new HTuple(), hv_Column = new HTuple(), hv_Rectangularity; HTuple hv_SortedIndex, hv_IndexBest, hv_MinContrast, hv_NumberCand; HTuple hv_Area, hv_Dummy, hv_DummyS, hv_AreaMedian; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Caltab); HOperatorSet.GenEmptyObj(out ho_Marks); HOperatorSet.GenEmptyObj(out ho_ImageMean); HOperatorSet.GenEmptyObj(out ho_RegionDynThresh); HOperatorSet.GenEmptyObj(out ho_RegionBorder); HOperatorSet.GenEmptyObj(out ho_RegionOpening1); HOperatorSet.GenEmptyObj(out ho_ConnectedRegions1); HOperatorSet.GenEmptyObj(out ho_SelectedRegions4); HOperatorSet.GenEmptyObj(out ho_SelectedRegions5); HOperatorSet.GenEmptyObj(out ho_RegionBorder2); HOperatorSet.GenEmptyObj(out ho_RegionTrans); HOperatorSet.GenEmptyObj(out ho_RegionErosion); HOperatorSet.GenEmptyObj(out ho_RegionBorder1); HOperatorSet.GenEmptyObj(out ho_RegionDilation2); HOperatorSet.GenEmptyObj(out ho_RegionDifference1); HOperatorSet.GenEmptyObj(out ho_RegionOpening); HOperatorSet.GenEmptyObj(out ho_ConnectedRegions); HOperatorSet.GenEmptyObj(out ho_SelectedRegions2); HOperatorSet.GenEmptyObj(out ho_SelectedRegions); HOperatorSet.GenEmptyObj(out ho_RegionFillUp); HOperatorSet.GenEmptyObj(out ho_SelectedRegions1); HOperatorSet.GenEmptyObj(out ho_RegionIntersection); HOperatorSet.GenEmptyObj(out ho_RegionFillUp1); HOperatorSet.GenEmptyObj(out ho_RegionDifference); HOperatorSet.GenEmptyObj(out ho_CaltabCandidates); HOperatorSet.GenEmptyObj(out ho_ObjectSelected); HOperatorSet.GenEmptyObj(out ho_ConnectedMarks); HOperatorSet.GenEmptyObj(out ho_ObjectSelectedCaltab); HOperatorSet.GenEmptyObj(out ho_RegionFillUpCand); HOperatorSet.GenEmptyObj(out ho_MarksCand); HOperatorSet.GenEmptyObj(out ho_RegionDilation1); HOperatorSet.GenEmptyObj(out ho_ImageReduced); HOperatorSet.GenEmptyObj(out ho_DefaultEdges); HOperatorSet.GenEmptyObj(out ho_UnionContours); HOperatorSet.GenEmptyObj(out ho_SelectedXLD); HOperatorSet.GenEmptyObj(out ho_SelectedXLD1); // ho_Marks.Dispose(); HOperatorSet.GenEmptyObj(out ho_Marks); ho_Caltab.Dispose(); HOperatorSet.GenEmptyObj(out ho_Caltab); HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height); hv_EstimatedCaltabSize = (((((hv_Width.TupleConcat(hv_Height))).TupleMax()) / 2.5)).TupleRound() ; hv_EstimatedMarkSize = ((hv_EstimatedCaltabSize / 12.0)).TupleRound(); ho_ImageMean.Dispose(); HOperatorSet.MeanImage(ho_Image, out ho_ImageMean, hv_EstimatedMarkSize * 3, hv_EstimatedMarkSize * 3); ho_RegionDynThresh.Dispose(); HOperatorSet.DynThreshold(ho_Image, ho_ImageMean, out ho_RegionDynThresh, 3, "light"); ho_RegionBorder.Dispose(); HOperatorSet.DynThreshold(ho_Image, ho_ImageMean, out ho_RegionBorder, 20, "dark"); ho_RegionOpening1.Dispose(); HOperatorSet.OpeningCircle(ho_RegionBorder, out ho_RegionOpening1, 1.5); ho_ConnectedRegions1.Dispose(); HOperatorSet.Connection(ho_RegionOpening1, out ho_ConnectedRegions1); ho_SelectedRegions4.Dispose(); HOperatorSet.SelectShape(ho_ConnectedRegions1, out ho_SelectedRegions4, "compactness", "and", 17, 50); ho_SelectedRegions5.Dispose(); HOperatorSet.SelectShape(ho_SelectedRegions4, out ho_SelectedRegions5, "anisometry", "and", 1, 1.4); ho_RegionBorder2.Dispose(); HOperatorSet.Boundary(ho_SelectedRegions5, out ho_RegionBorder2, "outer"); ho_SelectedRegions5.Dispose(); HOperatorSet.SelectShape(ho_RegionBorder2, out ho_SelectedRegions5, "circularity", "and", 0.006, 1); ho_RegionTrans.Dispose(); HOperatorSet.ShapeTrans(ho_SelectedRegions5, out ho_RegionTrans, "rectangle2"); ho_RegionErosion.Dispose(); HOperatorSet.ErosionCircle(ho_RegionTrans, out ho_RegionErosion, (hv_Width / 640.0) * 5.5); ho_RegionBorder1.Dispose(); HOperatorSet.Boundary(ho_RegionErosion, out ho_RegionBorder1, "inner"); ho_RegionDilation2.Dispose(); HOperatorSet.DilationCircle(ho_RegionBorder1, out ho_RegionDilation2, 3.5); ho_RegionDifference1.Dispose(); HOperatorSet.Difference(ho_RegionDynThresh, ho_RegionDilation2, out ho_RegionDifference1 ); ho_RegionOpening.Dispose(); HOperatorSet.OpeningCircle(ho_RegionDifference1, out ho_RegionOpening, (hv_Width / 640) * 1.5); ho_ConnectedRegions.Dispose(); HOperatorSet.Connection(ho_RegionOpening, out ho_ConnectedRegions); ho_SelectedRegions2.Dispose(); HOperatorSet.SelectShape(ho_ConnectedRegions, out ho_SelectedRegions2, "area", "and", (hv_EstimatedCaltabSize.TuplePow(2)) / 10, (hv_EstimatedCaltabSize.TuplePow( 2)) * 5); ho_SelectedRegions.Dispose(); HOperatorSet.SelectShape(ho_SelectedRegions2, out ho_SelectedRegions, "compactness", "and", 1.4, 10); ho_RegionFillUp.Dispose(); HOperatorSet.FillUp(ho_SelectedRegions, out ho_RegionFillUp); ho_SelectedRegions1.Dispose(); HOperatorSet.SelectShape(ho_RegionFillUp, out ho_SelectedRegions1, "rectangularity", "and", 0.6, 1); ho_RegionIntersection.Dispose(); HOperatorSet.Intersection(ho_SelectedRegions1, ho_RegionDynThresh, out ho_RegionIntersection ); ho_RegionFillUp1.Dispose(); HOperatorSet.FillUp(ho_RegionIntersection, out ho_RegionFillUp1); ho_RegionDifference.Dispose(); HOperatorSet.Difference(ho_RegionFillUp1, ho_RegionIntersection, out ho_RegionDifference ); HOperatorSet.CountObj(ho_RegionDifference, out hv_Number); ho_CaltabCandidates.Dispose(); HOperatorSet.GenEmptyObj(out ho_CaltabCandidates); HOperatorSet.CaltabPoints(hv_DescriptionFileName, out hv_X, out hv_Y, out hv_Z); hv_NumDescrMarks = new HTuple(hv_X.TupleLength()); for (hv_Index = 1; hv_Index.Continue(hv_Number, 1); hv_Index = hv_Index.TupleAdd(1)) { ho_ObjectSelected.Dispose(); HOperatorSet.SelectObj(ho_RegionDifference, out ho_ObjectSelected, hv_Index); ho_ConnectedMarks.Dispose(); HOperatorSet.Connection(ho_ObjectSelected, out ho_ConnectedMarks); HOperatorSet.CountObj(ho_ConnectedMarks, out hv_NumberMarks); HOperatorSet.Eccentricity(ho_ConnectedMarks, out hv_Anisometry, out hv_Bulkiness, out hv_StructureFactor); HOperatorSet.AreaCenter(ho_ConnectedMarks, out hv_AreaMarks, out hv_Row, out hv_Column); ho_ObjectSelectedCaltab.Dispose(); HOperatorSet.SelectObj(ho_RegionIntersection, out ho_ObjectSelectedCaltab, hv_Index); if ((int)((new HTuple((new HTuple((new HTuple(hv_NumberMarks.TupleGreaterEqual( 10))).TupleAnd(new HTuple(hv_NumberMarks.TupleLess(hv_NumDescrMarks + 20))))).TupleAnd( new HTuple(((((hv_Anisometry.TupleSort())).TupleSelect((new HTuple(hv_Anisometry.TupleLength() )) / 2))).TupleLess(2))))).TupleAnd(new HTuple((new HTuple(hv_AreaMarks.TupleMean() )).TupleGreater(20)))) != 0) { HOperatorSet.ConcatObj(ho_CaltabCandidates, ho_ObjectSelectedCaltab, out OTemp[0] ); ho_CaltabCandidates.Dispose(); ho_CaltabCandidates = OTemp[0]; } } ho_RegionFillUpCand.Dispose(); HOperatorSet.FillUp(ho_CaltabCandidates, out ho_RegionFillUpCand); HOperatorSet.Rectangularity(ho_RegionFillUpCand, out hv_Rectangularity); if ((int)(new HTuple((new HTuple(hv_Rectangularity.TupleLength())).TupleEqual( 0))) != 0) { ho_ImageMean.Dispose(); ho_RegionDynThresh.Dispose(); ho_RegionBorder.Dispose(); ho_RegionOpening1.Dispose(); ho_ConnectedRegions1.Dispose(); ho_SelectedRegions4.Dispose(); ho_SelectedRegions5.Dispose(); ho_RegionBorder2.Dispose(); ho_RegionTrans.Dispose(); ho_RegionErosion.Dispose(); ho_RegionBorder1.Dispose(); ho_RegionDilation2.Dispose(); ho_RegionDifference1.Dispose(); ho_RegionOpening.Dispose(); ho_ConnectedRegions.Dispose(); ho_SelectedRegions2.Dispose(); ho_SelectedRegions.Dispose(); ho_RegionFillUp.Dispose(); ho_SelectedRegions1.Dispose(); ho_RegionIntersection.Dispose(); ho_RegionFillUp1.Dispose(); ho_RegionDifference.Dispose(); ho_CaltabCandidates.Dispose(); ho_ObjectSelected.Dispose(); ho_ConnectedMarks.Dispose(); ho_ObjectSelectedCaltab.Dispose(); ho_RegionFillUpCand.Dispose(); ho_MarksCand.Dispose(); ho_RegionDilation1.Dispose(); ho_ImageReduced.Dispose(); ho_DefaultEdges.Dispose(); ho_UnionContours.Dispose(); ho_SelectedXLD.Dispose(); ho_SelectedXLD1.Dispose(); return; } hv_SortedIndex = hv_Rectangularity.TupleSortIndex(); hv_IndexBest = (((hv_SortedIndex.TupleInverse())).TupleSelect(0)) + 1; ho_Caltab.Dispose(); HOperatorSet.SelectObj(ho_RegionFillUpCand, out ho_Caltab, hv_IndexBest); ho_RegionFillUp.Dispose(); HOperatorSet.FillUp(ho_Caltab, out ho_RegionFillUp); ho_MarksCand.Dispose(); HOperatorSet.Difference(ho_RegionFillUp, ho_RegionDynThresh, out ho_MarksCand ); ho_RegionBorder.Dispose(); HOperatorSet.Boundary(ho_MarksCand, out ho_RegionBorder, "inner"); ho_RegionDilation1.Dispose(); HOperatorSet.DilationCircle(ho_RegionBorder, out ho_RegionDilation1, 9.5); ho_ImageReduced.Dispose(); HOperatorSet.ReduceDomain(ho_Image, ho_RegionDilation1, out ho_ImageReduced); hv_MinContrast = 10; ho_DefaultEdges.Dispose(); HOperatorSet.EdgesSubPix(ho_ImageReduced, out ho_DefaultEdges, "canny", 2, hv_MinContrast / 2, hv_MinContrast); HOperatorSet.CountObj(ho_DefaultEdges, out hv_NumberCand); if ((int)(new HTuple(hv_NumberCand.TupleLess(10))) != 0) { ho_ImageMean.Dispose(); ho_RegionDynThresh.Dispose(); ho_RegionBorder.Dispose(); ho_RegionOpening1.Dispose(); ho_ConnectedRegions1.Dispose(); ho_SelectedRegions4.Dispose(); ho_SelectedRegions5.Dispose(); ho_RegionBorder2.Dispose(); ho_RegionTrans.Dispose(); ho_RegionErosion.Dispose(); ho_RegionBorder1.Dispose(); ho_RegionDilation2.Dispose(); ho_RegionDifference1.Dispose(); ho_RegionOpening.Dispose(); ho_ConnectedRegions.Dispose(); ho_SelectedRegions2.Dispose(); ho_SelectedRegions.Dispose(); ho_RegionFillUp.Dispose(); ho_SelectedRegions1.Dispose(); ho_RegionIntersection.Dispose(); ho_RegionFillUp1.Dispose(); ho_RegionDifference.Dispose(); ho_CaltabCandidates.Dispose(); ho_ObjectSelected.Dispose(); ho_ConnectedMarks.Dispose(); ho_ObjectSelectedCaltab.Dispose(); ho_RegionFillUpCand.Dispose(); ho_MarksCand.Dispose(); ho_RegionDilation1.Dispose(); ho_ImageReduced.Dispose(); ho_DefaultEdges.Dispose(); ho_UnionContours.Dispose(); ho_SelectedXLD.Dispose(); ho_SelectedXLD1.Dispose(); return; } ho_UnionContours.Dispose(); HOperatorSet.UnionCocircularContoursXld(ho_DefaultEdges, out ho_UnionContours, 0.5, 0.1, 0.2, 30, 10, 10, "true", 1); ho_SelectedXLD.Dispose(); HOperatorSet.SelectShapeXld(ho_UnionContours, out ho_SelectedXLD, "area", "and", 30, 10000); ho_SelectedXLD1.Dispose(); HOperatorSet.SelectShapeXld(ho_SelectedXLD, out ho_SelectedXLD1, "circularity", "and", 0.4, 1); ho_MarksCand.Dispose(); HOperatorSet.SelectShapeXld(ho_SelectedXLD1, out ho_MarksCand, "compactness", "and", 1, 1.5); HOperatorSet.AreaCenterXld(ho_MarksCand, out hv_Area, out hv_Dummy, out hv_Dummy, out hv_DummyS); HOperatorSet.CountObj(ho_MarksCand, out hv_Number); if ((int)(new HTuple(hv_Number.TupleLess(4))) != 0) { ho_ImageMean.Dispose(); ho_RegionDynThresh.Dispose(); ho_RegionBorder.Dispose(); ho_RegionOpening1.Dispose(); ho_ConnectedRegions1.Dispose(); ho_SelectedRegions4.Dispose(); ho_SelectedRegions5.Dispose(); ho_RegionBorder2.Dispose(); ho_RegionTrans.Dispose(); ho_RegionErosion.Dispose(); ho_RegionBorder1.Dispose(); ho_RegionDilation2.Dispose(); ho_RegionDifference1.Dispose(); ho_RegionOpening.Dispose(); ho_ConnectedRegions.Dispose(); ho_SelectedRegions2.Dispose(); ho_SelectedRegions.Dispose(); ho_RegionFillUp.Dispose(); ho_SelectedRegions1.Dispose(); ho_RegionIntersection.Dispose(); ho_RegionFillUp1.Dispose(); ho_RegionDifference.Dispose(); ho_CaltabCandidates.Dispose(); ho_ObjectSelected.Dispose(); ho_ConnectedMarks.Dispose(); ho_ObjectSelectedCaltab.Dispose(); ho_RegionFillUpCand.Dispose(); ho_MarksCand.Dispose(); ho_RegionDilation1.Dispose(); ho_ImageReduced.Dispose(); ho_DefaultEdges.Dispose(); ho_UnionContours.Dispose(); ho_SelectedXLD.Dispose(); ho_SelectedXLD1.Dispose(); return; } hv_AreaMedian = ((hv_Area.TupleSort())).TupleSelect(hv_Number / 2); ho_Marks.Dispose(); HOperatorSet.SelectShapeXld(ho_MarksCand, out ho_Marks, "area", "and", hv_AreaMedian - (hv_AreaMedian * 0.5), hv_AreaMedian + (hv_AreaMedian * 0.5)); ho_ImageMean.Dispose(); ho_RegionDynThresh.Dispose(); ho_RegionBorder.Dispose(); ho_RegionOpening1.Dispose(); ho_ConnectedRegions1.Dispose(); ho_SelectedRegions4.Dispose(); ho_SelectedRegions5.Dispose(); ho_RegionBorder2.Dispose(); ho_RegionTrans.Dispose(); ho_RegionErosion.Dispose(); ho_RegionBorder1.Dispose(); ho_RegionDilation2.Dispose(); ho_RegionDifference1.Dispose(); ho_RegionOpening.Dispose(); ho_ConnectedRegions.Dispose(); ho_SelectedRegions2.Dispose(); ho_SelectedRegions.Dispose(); ho_RegionFillUp.Dispose(); ho_SelectedRegions1.Dispose(); ho_RegionIntersection.Dispose(); ho_RegionFillUp1.Dispose(); ho_RegionDifference.Dispose(); ho_CaltabCandidates.Dispose(); ho_ObjectSelected.Dispose(); ho_ConnectedMarks.Dispose(); ho_ObjectSelectedCaltab.Dispose(); ho_RegionFillUpCand.Dispose(); ho_MarksCand.Dispose(); ho_RegionDilation1.Dispose(); ho_ImageReduced.Dispose(); ho_DefaultEdges.Dispose(); ho_UnionContours.Dispose(); ho_SelectedXLD.Dispose(); ho_SelectedXLD1.Dispose(); return; } /// /// Determines whether the calibration image is overexposed /// public void eval_caltab_overexposure(HObject ho_Image, HObject ho_Caltab, out HTuple hv_OverexposureScore) { // Local iconic variables HObject ho_ImageReduced, ho_Region; // Local control variables HTuple hv_AreaCaltab, hv_Row, hv_Column, hv_AreaOverExp; HTuple hv_Thresh, hv_Ratio; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_ImageReduced); HOperatorSet.GenEmptyObj(out ho_Region); //returns a measure of the amount of saturation of the plate hv_OverexposureScore = 0.0; HOperatorSet.AreaCenter(ho_Caltab, out hv_AreaCaltab, out hv_Row, out hv_Column); if ((int)((new HTuple(hv_AreaCaltab.TupleEqual(0))).TupleOr(new HTuple(hv_AreaCaltab.TupleEqual( new HTuple())))) != 0) { ho_ImageReduced.Dispose(); ho_Region.Dispose(); return; } ho_ImageReduced.Dispose(); HOperatorSet.ReduceDomain(ho_Image, ho_Caltab, out ho_ImageReduced); ho_Region.Dispose(); HOperatorSet.Threshold(ho_ImageReduced, out ho_Region, 255, 255); HOperatorSet.AreaCenter(ho_Region, out hv_AreaOverExp, out hv_Row, out hv_Column); hv_Thresh = 0.15; hv_Ratio = (hv_AreaOverExp.TupleReal()) / hv_AreaCaltab; if ((int)(new HTuple(hv_Ratio.TupleLess(hv_Thresh))) != 0) { hv_OverexposureScore = (((new HTuple(1.0)).TupleConcat(1 - (hv_Ratio / hv_Thresh)))).TupleMin() ; } ho_ImageReduced.Dispose(); ho_Region.Dispose(); return; } /// /// Evaluates the gray value contrast between the marks and the calibration /// plate and the homogeneity of the used illumination. /// public void eval_caltab_contrast_homogeneity(HObject ho_Image, HObject ho_Marks, out HTuple hv_Contrast, out HTuple hv_ContrastScore, out HTuple hv_HomogeneityScore) { // Local iconic variables HObject ho_Region, ho_RegionDilation; // Local control variables HTuple hv_Number, hv_Min, hv_Max, hv_Range; HTuple hv_MinContrast, hv_MaxContrast, hv_DeviationMax; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Region); HOperatorSet.GenEmptyObj(out ho_RegionDilation); hv_ContrastScore = 0.0; hv_Contrast = 0.0; hv_HomogeneityScore = 0.0; HOperatorSet.CountObj(ho_Marks, out hv_Number); if ((int)(new HTuple(hv_Number.TupleLess(4))) != 0) { ho_Region.Dispose(); ho_RegionDilation.Dispose(); return; } ho_Region.Dispose(); HOperatorSet.GenRegionContourXld(ho_Marks, out ho_Region, "margin"); ho_RegionDilation.Dispose(); HOperatorSet.DilationCircle(ho_Region, out ho_RegionDilation, 5.5); HOperatorSet.MinMaxGray(ho_RegionDilation, ho_Image, 3, out hv_Min, out hv_Max, out hv_Range); //Calculate contrast score hv_Contrast = hv_Range.TupleMean(); hv_MinContrast = 70; hv_MaxContrast = 160; if ((int)(new HTuple(hv_Contrast.TupleGreater(hv_MinContrast))) != 0) { hv_ContrastScore = (hv_Contrast - hv_MinContrast) / (hv_MaxContrast - hv_MinContrast); hv_ContrastScore = ((hv_ContrastScore.TupleConcat(1.0))).TupleMin(); } //Now for the homogeneity score HOperatorSet.TupleDeviation(hv_Max, out hv_DeviationMax); hv_HomogeneityScore = 1.1 - (hv_DeviationMax / 40.0); hv_HomogeneityScore = ((((((hv_HomogeneityScore.TupleConcat(1.0))).TupleMin() )).TupleConcat(0.0))).TupleMax(); ho_Region.Dispose(); ho_RegionDilation.Dispose(); return; } /// /// Evaluates the area covered by the calibration plate in the calibration /// image. /// public void eval_caltab_size(HObject ho_Image, HObject ho_Caltab, HObject ho_Marks, out HTuple hv_SizeScore) { // Local iconic variables HObject ho_Region = null, ho_RegionUnion = null; // Local control variables HTuple hv_Width, hv_Height, hv_Number, hv_Row1 = new HTuple(); HTuple hv_Column1 = new HTuple(), hv_Phi1 = new HTuple(), hv_Length1 = new HTuple(); HTuple hv_Length2 = new HTuple(), hv_Area = new HTuple(), hv_Row = new HTuple(); HTuple hv_Column = new HTuple(), hv_MinRatio, hv_MaxRatio; HTuple hv_Ratio; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Region); HOperatorSet.GenEmptyObj(out ho_RegionUnion); hv_SizeScore = 0.0; HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height); HOperatorSet.CountObj(ho_Marks, out hv_Number); if ((int)(new HTuple(hv_Number.TupleGreaterEqual(4))) != 0) { //Best approach: Use the surrounding box of the marks as reference size ho_Region.Dispose(); HOperatorSet.GenRegionContourXld(ho_Marks, out ho_Region, "filled"); ho_RegionUnion.Dispose(); HOperatorSet.Union1(ho_Region, out ho_RegionUnion); HOperatorSet.SmallestRectangle2(ho_RegionUnion, out hv_Row1, out hv_Column1, out hv_Phi1, out hv_Length1, out hv_Length2); hv_Area = (hv_Length2 * hv_Length1) * 4; } else { //If no marks could be found: use the caltab as reference size HOperatorSet.AreaCenter(ho_Caltab, out hv_Area, out hv_Row, out hv_Column); if ((int)((new HTuple(hv_Area.TupleEqual(0))).TupleOr(new HTuple(hv_Area.TupleEqual( new HTuple())))) != 0) { ho_Region.Dispose(); ho_RegionUnion.Dispose(); return; } } hv_MinRatio = 0.015; hv_MaxRatio = 0.075; hv_Ratio = (hv_Area.TupleReal()) / (hv_Width * hv_Height); if ((int)(new HTuple(hv_Ratio.TupleGreater(hv_MinRatio))) != 0) { hv_SizeScore = (hv_Ratio - hv_MinRatio) / (hv_MaxRatio - hv_MinRatio); hv_SizeScore = (((new HTuple(1.0)).TupleConcat(hv_SizeScore))).TupleMin(); } ho_Region.Dispose(); ho_RegionUnion.Dispose(); return; } /// /// Display the axes of a 3d coordinate system. /// private void disp_3d_coord_system(HTuple hv_WindowHandle, HTuple hv_CamParam, HTuple hv_Pose, HTuple hv_CoordAxesLength) { // Local iconic variables HObject ho_ContX, ho_ContY, ho_ContZ; // Local control variables HTuple hv_TransWorld2Cam, hv_OrigCamX, hv_OrigCamY; HTuple hv_OrigCamZ, hv_Row0, hv_Column0, hv_X, hv_Y, hv_Z; HTuple hv_RowAxX, hv_ColumnAxX, hv_RowAxY, hv_ColumnAxY; HTuple hv_RowAxZ, hv_ColumnAxZ; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_ContX); HOperatorSet.GenEmptyObj(out ho_ContY); HOperatorSet.GenEmptyObj(out ho_ContZ); if ((int)(new HTuple((new HTuple(hv_Pose.TupleLength())).TupleNotEqual(7))) != 0) { ho_ContX.Dispose(); ho_ContY.Dispose(); ho_ContZ.Dispose(); return; } if ((int)(new HTuple(((hv_Pose.TupleSelect(5))).TupleEqual(0.0))) != 0) { ho_ContX.Dispose(); ho_ContY.Dispose(); ho_ContZ.Dispose(); return; } HOperatorSet.PoseToHomMat3d(hv_Pose, out hv_TransWorld2Cam); //Project the world origin into the image HOperatorSet.AffineTransPoint3d(hv_TransWorld2Cam, 0, 0, 0, out hv_OrigCamX, out hv_OrigCamY, out hv_OrigCamZ); HOperatorSet.Project3dPoint(hv_OrigCamX, hv_OrigCamY, hv_OrigCamZ, hv_CamParam, out hv_Row0, out hv_Column0); //Project the coordinate axes into the image HOperatorSet.AffineTransPoint3d(hv_TransWorld2Cam, hv_CoordAxesLength, 0, 0, out hv_X, out hv_Y, out hv_Z); HOperatorSet.Project3dPoint(hv_X, hv_Y, hv_Z, hv_CamParam, out hv_RowAxX, out hv_ColumnAxX); HOperatorSet.AffineTransPoint3d(hv_TransWorld2Cam, 0, hv_CoordAxesLength, 0, out hv_X, out hv_Y, out hv_Z); HOperatorSet.Project3dPoint(hv_X, hv_Y, hv_Z, hv_CamParam, out hv_RowAxY, out hv_ColumnAxY); HOperatorSet.AffineTransPoint3d(hv_TransWorld2Cam, 0, 0, hv_CoordAxesLength, out hv_X, out hv_Y, out hv_Z); HOperatorSet.Project3dPoint(hv_X, hv_Y, hv_Z, hv_CamParam, out hv_RowAxZ, out hv_ColumnAxZ); ho_ContX.Dispose(); gen_arrow_cont(out ho_ContX, hv_Row0, hv_Column0, hv_RowAxX, hv_ColumnAxX); ho_ContY.Dispose(); gen_arrow_cont(out ho_ContY, hv_Row0, hv_Column0, hv_RowAxY, hv_ColumnAxY); ho_ContZ.Dispose(); gen_arrow_cont(out ho_ContZ, hv_Row0, hv_Column0, hv_RowAxZ, hv_ColumnAxZ); if (HDevWindowStack.IsOpen()) { //dev_display (ContX) } if (HDevWindowStack.IsOpen()) { //dev_display (ContY) } if (HDevWindowStack.IsOpen()) { //dev_display (ContZ) } HOperatorSet.DispObj(ho_ContX, hv_WindowHandle); HOperatorSet.DispObj(ho_ContY, hv_WindowHandle); HOperatorSet.DispObj(ho_ContZ, hv_WindowHandle); HOperatorSet.SetTposition(hv_WindowHandle, hv_RowAxX + 3, hv_ColumnAxX + 3); HOperatorSet.WriteString(hv_WindowHandle, "X"); HOperatorSet.SetTposition(hv_WindowHandle, hv_RowAxY + 3, hv_ColumnAxY + 3); HOperatorSet.WriteString(hv_WindowHandle, "Y"); HOperatorSet.SetTposition(hv_WindowHandle, hv_RowAxZ + 3, hv_ColumnAxZ + 3); HOperatorSet.WriteString(hv_WindowHandle, "Z"); ho_ContX.Dispose(); ho_ContY.Dispose(); ho_ContZ.Dispose(); return; } /// /// Generate a contour in form of an arrow. /// private void gen_arrow_cont(out HObject ho_Arrow, HTuple hv_Row1, HTuple hv_Column1, HTuple hv_Row2, HTuple hv_Column2) { // Local iconic variables HObject ho_Cross1, ho_Cross2, ho_CrossP1, ho_CrossP2; // Local control variables HTuple hv_Length, hv_Angle, hv_MinArrowLength; HTuple hv_DRow, hv_DCol, hv_ArrowLength, hv_Phi, hv_P1R; HTuple hv_P1C, hv_P2R, hv_P2C; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Arrow); HOperatorSet.GenEmptyObj(out ho_Cross1); HOperatorSet.GenEmptyObj(out ho_Cross2); HOperatorSet.GenEmptyObj(out ho_CrossP1); HOperatorSet.GenEmptyObj(out ho_CrossP2); //Generate a contour in form of a arrow hv_Length = 7; hv_Angle = 40; hv_MinArrowLength = 2; hv_DRow = hv_Row2 - hv_Row1; hv_DCol = hv_Column2 - hv_Column1; hv_ArrowLength = (((hv_DRow * hv_DRow) + (hv_DCol * hv_DCol))).TupleSqrt(); if ((int)(new HTuple(hv_ArrowLength.TupleLess(hv_MinArrowLength))) != 0) { hv_Length = 0; } HOperatorSet.TupleAtan2(hv_DRow, -hv_DCol, out hv_Phi); hv_P1R = hv_Row2 - (hv_Length * (((hv_Phi - (hv_Angle.TupleRad()))).TupleSin())); hv_P1C = hv_Column2 + (hv_Length * (((hv_Phi - (hv_Angle.TupleRad()))).TupleCos())); hv_P2R = hv_Row2 - (hv_Length * (((hv_Phi + (hv_Angle.TupleRad()))).TupleSin())); hv_P2C = hv_Column2 + (hv_Length * (((hv_Phi + (hv_Angle.TupleRad()))).TupleCos())); ho_Cross1.Dispose(); HOperatorSet.GenCrossContourXld(out ho_Cross1, hv_Row1, hv_Column1, 6, 0.785398); ho_Cross2.Dispose(); HOperatorSet.GenCrossContourXld(out ho_Cross2, hv_Row2, hv_Column2, 6, 0.785398); ho_CrossP1.Dispose(); HOperatorSet.GenCrossContourXld(out ho_CrossP1, hv_P1R, hv_P1C, 6, 0.785398); ho_CrossP2.Dispose(); HOperatorSet.GenCrossContourXld(out ho_CrossP2, hv_P2R, hv_P2C, 6, 0.785398); ho_Arrow.Dispose(); HOperatorSet.GenContourPolygonXld(out ho_Arrow, ((((((hv_Row1.TupleConcat(hv_Row2))).TupleConcat( hv_P1R))).TupleConcat(hv_Row2))).TupleConcat(hv_P2R), ((((((hv_Column1.TupleConcat( hv_Column2))).TupleConcat(hv_P1C))).TupleConcat(hv_Column2))).TupleConcat( hv_P2C)); ho_Cross1.Dispose(); ho_Cross2.Dispose(); ho_CrossP1.Dispose(); ho_CrossP2.Dispose(); return; } private void tuple_equal_greater(HTuple hv_Tuple, HTuple hv_Threshold, out HTuple hv_Selected, out HTuple hv_Indices) { // Local control variables HTuple hv_Sgn; // Initialize local and output iconic variables hv_Selected = new HTuple(); HOperatorSet.TupleSgn(hv_Tuple - hv_Threshold, out hv_Sgn); HOperatorSet.TupleFind(hv_Sgn, 1, out hv_Indices); if ((int)((new HTuple((new HTuple(hv_Indices.TupleLength())).TupleGreater(1))).TupleOr( new HTuple(((hv_Indices.TupleSelect(0))).TupleNotEqual(-1)))) != 0) { HOperatorSet.TupleSelect(hv_Tuple, hv_Indices, out hv_Selected); } return; } private void gen_fuzzy_weight_funct(HTuple hv_NPoints, HTuple hv_Min, HTuple hv_Max, HTuple hv_LowPass, HTuple hv_HighPass, out HTuple hv_FuzzyFunct) { // Local control variables HTuple hv_Ones, hv_Index, hv_X, hv_Y, hv_Dummy; HTuple hv_IndicesTrans, hv_IndicesHigh, hv_i, hv_NTransPoints; // Initialize local and output iconic variables //generates a function which is 0.0 for values lower than LowPass, 1.0 for //values over HighPass, and grows linearly for values in between the two HOperatorSet.TupleGenConst(hv_NPoints, 1, out hv_Ones); hv_Index = ((hv_Ones.TupleCumul()) - 1) / ((new HTuple(hv_Ones.TupleLength())).TupleReal() ); hv_X = (hv_Index * (hv_Max - hv_Min)) + hv_Min; HOperatorSet.TupleGenConst(new HTuple(hv_X.TupleLength()), 0.0, out hv_Y); tuple_equal_greater(hv_X, hv_LowPass, out hv_Dummy, out hv_IndicesTrans); tuple_equal_greater(hv_X, hv_HighPass, out hv_Dummy, out hv_IndicesHigh); //ramp from LowPass (0.0) to Highpass (1.0) hv_i = 0; while ((int)(new HTuple(((hv_IndicesTrans.TupleSelect(hv_i))).TupleLess(hv_IndicesHigh.TupleSelect( 0)))) != 0) { hv_i = hv_i + 1; } hv_NTransPoints = hv_i.Clone(); for (hv_i = 0; hv_i.Continue(hv_NTransPoints - 1, 1); hv_i = hv_i.TupleAdd(1)) { if (hv_Y == null) hv_Y = new HTuple(); hv_Y[hv_IndicesTrans.TupleSelect(hv_i)] = (hv_i.TupleReal()) / hv_NTransPoints; } for (hv_i = hv_IndicesTrans.TupleSelect(hv_NTransPoints); hv_i.Continue((new HTuple(hv_Y.TupleLength() )) - 1, 1); hv_i = hv_i.TupleAdd(1)) { if (hv_Y == null) hv_Y = new HTuple(); hv_Y[hv_i] = 1.0; } HOperatorSet.CreateFunct1dPairs(hv_X, hv_Y, out hv_FuzzyFunct); return; } /// /// Measures the tilt that is used for the plates in the set /// of calibration images. The more tilted plates are used /// in the image set, the better you can correct the radial /// distortion of the lense by performing the calibration. /// public void eval_caltab_tilt(HTuple hv_FinalPoses, out HTuple hv_TiltScore) { // Local control variables HTuple hv_NImages, hv_Ones, hv_Index, hv_Slant; HTuple hv_Pan, hv_FuzzyFunct, hv_SlantWeight, hv_PanWeight; HTuple hv_TmpPan, hv_TmpSlant; // Initialize local and output iconic variables hv_NImages = (new HTuple(hv_FinalPoses.TupleLength())) / 7; HOperatorSet.TupleGenConst(hv_NImages, 1, out hv_Ones); hv_Index = (hv_Ones.TupleCumul()) - 1; HOperatorSet.TupleSelect(hv_FinalPoses, (7 * hv_Index) + 3, out hv_Slant); HOperatorSet.TupleSelect(hv_FinalPoses, (7 * hv_Index) + 4, out hv_Pan); for (hv_Index = 0; (int)hv_Index <= (int)((new HTuple(hv_Slant.TupleLength())) - 1); hv_Index = (int)hv_Index + 1) { if ((int)(new HTuple(((hv_Slant.TupleSelect(hv_Index))).TupleGreater(180))) != 0) { if (hv_Slant == null) hv_Slant = new HTuple(); hv_Slant[hv_Index] = 360 - (hv_Slant.TupleSelect(hv_Index)); } } for (hv_Index = 0; (int)hv_Index <= (int)((new HTuple(hv_Pan.TupleLength())) - 1); hv_Index = (int)hv_Index + 1) { if ((int)(new HTuple(((hv_Pan.TupleSelect(hv_Index))).TupleGreater(180))) != 0) { if (hv_Pan == null) hv_Pan = new HTuple(); hv_Pan[hv_Index] = 360 - (hv_Pan.TupleSelect(hv_Index)); } } hv_Pan = hv_Pan.TupleRad(); hv_Slant = hv_Slant.TupleRad(); //function acting as a fuzzy weighting gen_fuzzy_weight_funct(256, (new HTuple(0.0)).TupleRad(), (new HTuple(90.0)).TupleRad() , (new HTuple(15.0)).TupleRad(), (new HTuple(40.0)).TupleRad(), out hv_FuzzyFunct); HOperatorSet.GetYValueFunct1d(hv_FuzzyFunct, hv_Slant, "constant", out hv_SlantWeight); HOperatorSet.GetYValueFunct1d(hv_FuzzyFunct, hv_Pan, "constant", out hv_PanWeight); //Calculate score value hv_TmpPan = (hv_PanWeight.TupleSum()) / 6; hv_TmpPan = ((hv_TmpPan.TupleConcat(0.5))).TupleMin(); hv_TmpSlant = (hv_SlantWeight.TupleSum()) / 6; hv_TmpSlant = ((hv_TmpSlant.TupleConcat(0.5))).TupleMin(); hv_TiltScore = hv_TmpSlant + hv_TmpPan; return; } /// /// Evaluates the distribution of the marks and hence the plates /// used for the calibration images. Precise measurements can only be /// achieved if the field view of the camera is covered well by the /// calibration plate in the images. /// public void eval_marks_distribution(HTuple hv_NRCoord, HTuple hv_NCCoord, HTuple hv_Width, HTuple hv_Height, out HTuple hv_MarksDistributionScore) { // Local iconic variables HObject ho_Region, ho_DistanceImage, ho_Mask; // Local control variables HTuple hv_Border, hv_Min, hv_Max, hv_Range; HTuple hv_ImageDiagonal, hv_MinThresh, hv_MaxThresh, hv_Ratio; HTuple hv_Tmp1, hv_Tmp2; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Region); HOperatorSet.GenEmptyObj(out ho_DistanceImage); HOperatorSet.GenEmptyObj(out ho_Mask); //Determine the distances between the marks centers ho_Region.Dispose(); HOperatorSet.GenRegionPoints(out ho_Region, hv_NRCoord, hv_NCCoord); ho_DistanceImage.Dispose(); HOperatorSet.DistanceTransform(ho_Region, out ho_DistanceImage, "octagonal", "false", hv_Width, hv_Height); //A clipping is needed because the marks cannot come close to the border hv_Border = (((hv_Width.TupleConcat(hv_Height))).TupleMax()) / 15; ho_Mask.Dispose(); HOperatorSet.GenRectangle1(out ho_Mask, hv_Border, hv_Border, (hv_Height - 1) - hv_Border, (hv_Width - 1) - hv_Border); HOperatorSet.MinMaxGray(ho_Mask, ho_DistanceImage, 0, out hv_Min, out hv_Max, out hv_Range); HOperatorSet.DistancePp(0, 0, hv_Height - 1, hv_Width - 1, out hv_ImageDiagonal); hv_MinThresh = 0.3; hv_MaxThresh = 0.85; hv_Ratio = (hv_Max / hv_ImageDiagonal) * 2.5; hv_Tmp1 = 1 - hv_Ratio; hv_Tmp2 = (hv_Tmp1 - hv_MinThresh) / (hv_MaxThresh - hv_MinThresh); hv_MarksDistributionScore = ((((((hv_Tmp2.TupleConcat(1.0))).TupleMin())).TupleConcat( 0.0))).TupleMax(); ho_Region.Dispose(); ho_DistanceImage.Dispose(); ho_Mask.Dispose(); return; } /// /// Auxiliary method for display purposes. Returns the coordinate system /// described by the parameters hv_CamParam and hv_Pose /// as an iconic object. /// public void get_3d_coord_system(HObject ho_ImageReference, out HObject ho_CoordSystemRegion, HTuple hv_CamParam, HTuple hv_Pose, HTuple hv_CoordAxesLength) { // Local iconic variables HObject ho_CoordSystemImage; // Local control variables HTuple hv_Width, hv_Height, hv_OldBG, hv_WindowHandle; // Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_CoordSystemRegion); HOperatorSet.GenEmptyObj(out ho_CoordSystemImage); HOperatorSet.GetImageSize(ho_ImageReference, out hv_Width, out hv_Height); HOperatorSet.GetWindowAttr("background_color", out hv_OldBG); HOperatorSet.SetWindowAttr("background_color", "black"); HOperatorSet.OpenWindow(0, 0, hv_Width, hv_Height, 0, "buffer", "", out hv_WindowHandle); HOperatorSet.SetWindowAttr("background_color", hv_OldBG); HOperatorSet.SetColor(hv_WindowHandle, "white"); HOperatorSet.SetPart(hv_WindowHandle, 0, 0, hv_Height - 1, hv_Width - 1); disp_3d_coord_system(hv_WindowHandle, hv_CamParam, hv_Pose, hv_CoordAxesLength); ho_CoordSystemImage.Dispose(); HOperatorSet.DumpWindowImage(out ho_CoordSystemImage, hv_WindowHandle); HOperatorSet.CloseWindow(hv_WindowHandle); ho_CoordSystemRegion.Dispose(); HOperatorSet.Threshold(ho_CoordSystemImage, out ho_CoordSystemRegion, 255, 255); ho_CoordSystemImage.Dispose(); return; } } }