public static bool CheckTeacherROIOrientation(WaferOrientation patternOrientation, TeacherROIOrientaion teacherOrientation) { if (patternOrientation == WaferOrientation.Bottom || patternOrientation == WaferOrientation.Top) { if (teacherOrientation == TeacherROIOrientaion.Vertical) { throw new Exception("Teacher ROI Orientation Mismatch. Please switch between Horizontal and Vertical"); } } else if (patternOrientation == WaferOrientation.Left || patternOrientation == WaferOrientation.Right) { if (teacherOrientation == TeacherROIOrientaion.Horizontal) { throw new Exception("Teacher ROI Orientation Mismatch. Please switch between Horizontal and Vertical"); } } return(true); }
/// <summary> /// Calculate the midpoint of point1 and point2 /// Draw a line from the midpoint to referencePoint /// /// CCW -> positive /// CW -> negative /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> public static double Execute( PointF p1, PointF p2, PointF centerpoint, double referenceAngle_deg, bool IsConvertToDegree, WaferOrientation patternOrientation) { VisionLogger.Log(WaftechLibraries.Log.LogType.Log, "CalculateAngleBetween3Points", "Calculate Angle Between Three Points Started"); double midPointX = (p1.X + p2.X) / 2.0; double midPointY = (p1.Y + p2.Y) / 2.0; double centerX = centerpoint.X; double centerY = centerpoint.Y; double deltaX = midPointX - centerX; double deltaY = midPointY - centerY; double theta_rad; if (patternOrientation == WaferOrientation.Bottom) { if (deltaX < 0) { theta_rad = Math.Atan(Math.Abs(deltaX / deltaY)); } // CCW else { theta_rad = -Math.Atan(Math.Abs(deltaX / deltaY)); } // CW } else if (patternOrientation == WaferOrientation.Right) { if (deltaY > 0) { theta_rad = Math.Atan(Math.Abs(deltaY / deltaX)); } // CCW else { theta_rad = -Math.Atan(Math.Abs(deltaY / deltaX)); } // CW } else if (patternOrientation == WaferOrientation.Top) { if (deltaX > 0) { theta_rad = Math.Atan(Math.Abs(deltaX / deltaY)); } // CCW else { theta_rad = -Math.Atan(Math.Abs(deltaX / deltaY)); } // CW } else if (patternOrientation == WaferOrientation.Left) { if (deltaY < 0) { theta_rad = Math.Atan(Math.Abs(deltaY / deltaX)); } // CCW else { theta_rad = -Math.Atan(Math.Abs(deltaY / deltaX)); } // CW } else { throw new Exception("Invalid notch Orientation"); } double thetaOffset_rad; thetaOffset_rad = theta_rad - ConvertToRad(referenceAngle_deg); if (IsConvertToDegree) { return(ConvertToDeg(thetaOffset_rad)); } else { return(thetaOffset_rad); } }
public static PatternMatchingTransformationResult ExecuteWithoutRotation( EImageBW8 eImage, float max_XTranslateOffset, float max_YTranslateOffset, int maxNumberOfTrial, PatternMatcherParameters patternMatcherParameters, ELineGauge gauge1, ELineGauge gauge2, ELineGauge gauge3, ELineGauge gauge4, double filterTolerance, double fiducialOffset, WaferOrientation fiducialOrientation, bool isIncludeFiducialTolerance, Func <ELineGauge, ELineGauge, ELineGauge, ELineGauge, EImageBW8, double, double, WaferOrientation, bool, PointF> FindCenter) { List <string> messages = new List <string>(); float thetaOffset = -1; float xOffset = -1; float yOffset = -1; bool isPass = false; bool isXOffsetWithinTolerance = false; bool isYOffsetWithinTolerance = false; int xTranslationCount = -1; int yTranslationCount = -1; PointF calibratedCenterPoint = new PointF( patternMatcherParameters.WaferCenterXPos, patternMatcherParameters.WaferCenterYPos); PointF currentWaferCenterPoint = new PointF(-1, -1); EuresysDoubleMatcherResults matchedResult = null; messages.Add("Maximum NumberOfTrial is " + maxNumberOfTrial); messages.Add("Accepted X Offset is below " + max_XTranslateOffset); messages.Add("Accepted Y Offset is below " + max_YTranslateOffset); #region X Offset for (int i = 0; i < maxNumberOfTrial; i++) { // Find X Offset currentWaferCenterPoint = FindCenter.Invoke( gauge1, gauge2, gauge3, gauge4, eImage, filterTolerance, fiducialOffset, fiducialOrientation, isIncludeFiducialTolerance); xOffset = calibratedCenterPoint.X - currentWaferCenterPoint.X; if (Math.Abs(xOffset) < max_XTranslateOffset) { isXOffsetWithinTolerance = true; xTranslationCount = i; messages.Add("XOffset within tolerance"); messages.Add("Number of X tranlation performed = " + xTranslationCount); break; } else { isXOffsetWithinTolerance = false; messages.Add(string.Format("XOffset: {0} out of tolerance", xOffset)); eImage = ImageTransformer.TranslateImage_X(eImage, xOffset); messages.Add("Image X Translated by " + xOffset); } if (i == maxNumberOfTrial) { xTranslationCount = i; messages.Add("Maximum number of trials for XOffset reached"); } } #endregion XOffset #region Y Offset for (int i = 0; i <= maxNumberOfTrial; i++) { // Find Y Offset currentWaferCenterPoint = FindCenter.Invoke( gauge1, gauge2, gauge3, gauge4, eImage, filterTolerance, fiducialOffset, fiducialOrientation, isIncludeFiducialTolerance); yOffset = calibratedCenterPoint.Y - currentWaferCenterPoint.Y; if (Math.Abs(yOffset) < max_YTranslateOffset) { isYOffsetWithinTolerance = true; yTranslationCount = i; messages.Add("YOffset within tolerance"); messages.Add("Number of Y tranlation performed = " + yTranslationCount); break; } else { isYOffsetWithinTolerance = false; messages.Add(string.Format("YOffset: {0} out of tolerance", yOffset)); eImage = ImageTransformer.TranslateImage_Y(eImage, yOffset); messages.Add("Image Y Translated by " + yOffset); } if (i == maxNumberOfTrial) { yTranslationCount = i; messages.Add("Maximum number of trials for YOffset reached"); } } #endregion Y offset #region Theta Offset thetaOffset = 0; messages.Add("Theta Offset is skipped"); #endregion Theta Offset #region Final Result messages.Add("Final Angle is " + Math.Round(thetaOffset, 4)); messages.Add("Final X Offset is " + Math.Round(xOffset, 4)); messages.Add("Final Y Offset is " + Math.Round(yOffset, 4)); if (isXOffsetWithinTolerance && isYOffsetWithinTolerance) { isPass = true; messages.Add("Result is Pass"); } else { isPass = false; messages.Add("Result is False"); } return(new PatternMatchingTransformationResult() { MatchedResult = matchedResult, eImageAfterTransformation = eImage, FinalAngleOffset = thetaOffset, FinalXOffset = xOffset, FinalYOffset = yOffset, IsPass = isPass, IsThetaOffsetWithinTolerance = true, IsXOffsetWithinTolerance = isXOffsetWithinTolerance, IsYOffsetWithinTolerance = isXOffsetWithinTolerance, XTranlastionCount = xTranslationCount, YTranslationCount = yTranslationCount, ThetaTranslationCount = 0, FinalWaferCenter = currentWaferCenterPoint, Messages = messages, }); #endregion Final Result }
public static PatternMatchingTransformationResult Execute( EImageBW8 eImage, float max_AngleOffset, float max_XTranslateOffset, float max_YTranslateOffset, int maxNumberOfTrial, EuresysDoublePatternMatcher eMatcher, PatternMatcherParameters patternMatcherParameters, EROIBW8 matcherROI, ELineGauge gauge1, ELineGauge gauge2, ELineGauge gauge3, ELineGauge gauge4, double filterTolerance, double fiducialOffset, WaferOrientation fiducialOrientation, bool isIncludeFiducialTolerance, Func <ELineGauge, ELineGauge, ELineGauge, ELineGauge, EImageBW8, double, double, WaferOrientation, bool, PointF> FindCenter, PointF TeacherMidPoint) { List <string> messages = new List <string>(); float thetaOffset = -1; float xOffset = -1; float yOffset = -1; bool isPass = false; bool isThetaOffsetWithinTolerance = false; bool isXOffsetWithinTolerance = false; bool isYOffsetWithinTolerance = false; int xTranslationCount = -1; int yTranslationCount = -1; int thetaTranslationCount = -1; PointF calibratedCenterPoint = new PointF( patternMatcherParameters.WaferCenterXPos, patternMatcherParameters.WaferCenterYPos); PointF currentWaferCenterPoint = new PointF(-1, -1); EuresysDoubleMatcherResults matchedResult = null; messages.Add("Maximum NumberOfTrial is " + maxNumberOfTrial); messages.Add("Accepted AngleOffset is below " + max_AngleOffset); messages.Add("Accepted X Offset is below " + max_XTranslateOffset); messages.Add("Accepted Y Offset is below " + max_YTranslateOffset); #region X Offset for (int i = 0; i < maxNumberOfTrial; i++) { // Find X Offset currentWaferCenterPoint = FindCenter.Invoke( gauge1, gauge2, gauge3, gauge4, eImage, filterTolerance, fiducialOffset, fiducialOrientation, isIncludeFiducialTolerance); xOffset = calibratedCenterPoint.X - currentWaferCenterPoint.X; if (Math.Abs(xOffset) < max_XTranslateOffset) { isXOffsetWithinTolerance = true; xTranslationCount = i; messages.Add("XOffset within tolerance"); messages.Add("Number of X tranlation performed = " + xTranslationCount); break; } else { isXOffsetWithinTolerance = false; messages.Add(string.Format("XOffset: {0} out of tolerance", xOffset)); eImage = ImageTransformer.TranslateImage_X(eImage, xOffset); messages.Add("Image X Translated by " + xOffset); } if (i == maxNumberOfTrial) { xTranslationCount = i; messages.Add("Maximum number of trials for XOffset reached"); } } #endregion XOffset #region Y Offset for (int i = 0; i <= maxNumberOfTrial; i++) { // Find Y Offset currentWaferCenterPoint = FindCenter.Invoke( gauge1, gauge2, gauge3, gauge4, eImage, filterTolerance, fiducialOffset, fiducialOrientation, isIncludeFiducialTolerance); yOffset = calibratedCenterPoint.Y - currentWaferCenterPoint.Y; if (Math.Abs(yOffset) < max_YTranslateOffset) { isYOffsetWithinTolerance = true; yTranslationCount = i; messages.Add("YOffset within tolerance"); messages.Add("Number of Y tranlation performed = " + yTranslationCount); break; } else { isYOffsetWithinTolerance = false; messages.Add(string.Format("YOffset: {0} out of tolerance", yOffset)); eImage = ImageTransformer.TranslateImage_Y(eImage, yOffset); messages.Add("Image Y Translated by " + yOffset); } if (i == maxNumberOfTrial) { yTranslationCount = i; messages.Add("Maximum number of trials for YOffset reached"); } } #endregion Y offset #region Theta Offset if (isXOffsetWithinTolerance && isYOffsetWithinTolerance) { for (int i = 0; i <= maxNumberOfTrial; i++) { currentWaferCenterPoint = FindCenter.Invoke( gauge1, gauge2, gauge3, gauge4, eImage, filterTolerance, fiducialOffset, fiducialOrientation, isIncludeFiducialTolerance); EuresysEROIHelper.AttachROI(eImage, matcherROI); eMatcher.MatchPatterns(matcherROI); WaferOrientation patternOrientation = FindWaferOrientation(currentWaferCenterPoint, TeacherMidPoint); matchedResult = PatternMatcherParameterHelper.CreateDoublePatternMatcherResult( eMatcher, matcherROI, patternMatcherParameters.OriginalXPos_pattern1, patternMatcherParameters.OriginalYPos_pattern1, currentWaferCenterPoint, patternMatcherParameters.DefaultAngleOffset, patternOrientation); thetaOffset = matchedResult.AngleBetweenResult; if (thetaOffset > 180) { throw new ArgumentOutOfRangeException("theta Offset must not be higher than 180"); } else if (thetaOffset < -180) { throw new ArgumentOutOfRangeException("theta Offset must not be lesser than 180"); } if (Math.Abs(thetaOffset) < max_AngleOffset) { isThetaOffsetWithinTolerance = true; thetaTranslationCount = i; messages.Add("Theta Offset within tolerance"); messages.Add("Number of Theta tranlation performed = " + thetaTranslationCount); break; } else { isThetaOffsetWithinTolerance = false; messages.Add(string.Format("Theta Offset: {0} out of tolerance", thetaOffset)); eImage = ImageTransformer.RotateImage(eImage, thetaOffset, calibratedCenterPoint); messages.Add("Image Theta Rotated by " + thetaOffset + " around calibrated Center Point"); } if (i == maxNumberOfTrial) { thetaTranslationCount = i; messages.Add("Maximum number of trials for Theta Offset reached"); } } } else { if (!isXOffsetWithinTolerance) { messages.Add("Theta offset correction skipped due to X Offset out of tolerance"); } if (!isYOffsetWithinTolerance) { messages.Add("Theta offset correction skipped due to X Offset out of tolerance"); } } #endregion Theta Offset #region Final Result messages.Add("Final Angle is " + Math.Round(thetaOffset, 4)); messages.Add("Final X Offset is " + Math.Round(xOffset, 4)); messages.Add("Final Y Offset is " + Math.Round(yOffset, 4)); if (isThetaOffsetWithinTolerance && isXOffsetWithinTolerance && isYOffsetWithinTolerance) { isPass = true; messages.Add("Result is Pass"); } else { isPass = false; messages.Add("Result is False"); } return(new PatternMatchingTransformationResult() { MatchedResult = matchedResult, eImageAfterTransformation = eImage, FinalAngleOffset = thetaOffset, FinalXOffset = xOffset, FinalYOffset = yOffset, IsPass = isPass, IsThetaOffsetWithinTolerance = isThetaOffsetWithinTolerance, IsXOffsetWithinTolerance = isXOffsetWithinTolerance, IsYOffsetWithinTolerance = isXOffsetWithinTolerance, XTranlastionCount = xTranslationCount, YTranslationCount = yTranslationCount, ThetaTranslationCount = thetaTranslationCount, FinalWaferCenter = currentWaferCenterPoint, Messages = messages, }); #endregion Final Result }
public static EuresysDoubleMatcherResults CreateDoublePatternMatcherResult( EuresysDoublePatternMatcher matcher, EROIBW8 matcherEROI, float originalXPos_Pattern1, float originalYPos_Pattern1, PointF waferCenterPoint, double refAngle, WaferOrientation patternOrientation) { if (matcher == null) { throw new ArgumentNullException("matcher"); } if (!matcher.isPatternMatched_) { throw new ArgumentException("Pattern is not matched"); } if (matcher.EMatcher1.NumPositions < 1) { throw new ArgumentException("No occurance on EMatcher1"); } if (matcher.EMatcher2.NumPositions < 1) { throw new ArgumentException("No occurance on EMatcher2"); } if (matcher.EMatcher1.NumPositions > 1) { throw new ArgumentException("More than one occurance on EMatcher1"); } if (matcher.EMatcher2.NumPositions > 1) { throw new ArgumentException("More than one occurance on EMatcher2"); } if (matcher.EMatcher1.NumPositions != matcher.EMatcher2.NumPositions) { throw new ArgumentException("Occurance for EMatcher 1 and EMatcher 2 nota tally"); } EuresysDoubleMatcherResults result = new EuresysDoubleMatcherResults() { Angle1 = matcher.EMatcher1.GetPosition(0).Angle, ScaleX1 = matcher.EMatcher1.GetPosition(0).ScaleX, ScaleY1 = matcher.EMatcher1.GetPosition(0).ScaleY, CenterX1 = matcher.EMatcher1.GetPosition(0).CenterX + (float)(matcherEROI.OrgX), CenterY1 = matcher.EMatcher1.GetPosition(0).CenterY + (float)(matcherEROI.OrgY), Score1 = matcher.EMatcher1.GetPosition(0).Score, Angle2 = matcher.EMatcher2.GetPosition(0).Angle, ScaleX2 = matcher.EMatcher2.GetPosition(0).ScaleX, ScaleY2 = matcher.EMatcher2.GetPosition(0).ScaleY, CenterX2 = matcher.EMatcher2.GetPosition(0).CenterX + (float)(matcherEROI.OrgX), CenterY2 = matcher.EMatcher2.GetPosition(0).CenterY + (float)(matcherEROI.OrgY), Score2 = matcher.EMatcher2.GetPosition(0).Score, }; PointF p1 = new PointF(result.CenterX1, result.CenterY1); PointF p2 = new PointF(result.CenterX2, result.CenterY2); double angle = CalculateAngleBetween3Points.Execute(p1, p2, waferCenterPoint, refAngle, true, patternOrientation); if (angle > 45) { throw new Exception("angle should not be higher than 45 degree"); } if (angle < -45) { throw new Exception("angle should not be less than -45 degree"); } result.AngleBetweenResult = (float)angle; result.XOffset = originalXPos_Pattern1 - result.CenterX1; result.YOffset = originalYPos_Pattern1 - result.CenterY1; return(result); }
public static bool TeachTeacherROI( string RecipeName, EuresysDoublePatternMatcher PatternMatcher_, PatternMatcherParameters PatternMatcherParameters_, EROIBW8 eROIForPatternTeaching1_, EROIBW8 eROIForPatternTeaching2_, iEuresysROI MatcherEROI, PointF WaferCenterPoint, WaferOrientation patternOrientation) { string PatternFilePath_One = PatternMatcherParameterHelper.GetLeftPatternFilePath(RecipeName); string PatternFilePath_Two = PatternMatcherParameterHelper.GetRightPatternFilePath(RecipeName); string PatternImageFilePath_One = PatternMatcherParameterHelper.GetLeftPatternImageFilePath(RecipeName); string PatternImageFilePath_Two = PatternMatcherParameterHelper.GetRightPatternImageFilePath(RecipeName); PatternMatcher_.TeachAndSaveEMatcher( PatternMatcherParameters_, eROIForPatternTeaching1_, eROIForPatternTeaching2_, PatternFilePath_One, PatternFilePath_Two, PatternImageFilePath_One, PatternImageFilePath_Two); if (PatternMatcher_.Pattern1.IsVoid) { goto Fail; } if (PatternMatcher_.Pattern2.IsVoid) { goto Fail; } // Match EROIBW8 matcherROI = MatcherEROI.GetROI(0); PatternMatcher_.MatchPatterns(matcherROI); EMatcher eMatcher1 = PatternMatcher_.EMatcher1; EMatcher eMatcher2 = PatternMatcher_.EMatcher2; if (eMatcher1.NumPositions != 1) { string errorMessage = "Pattern 1: Number of patterns matched is not equal to one"; VisionLogger.Log(LogType.Exception, "PatternMatcherManager", errorMessage); VisionNotifier.AddNotification(errorMessage); goto Fail; } if (eMatcher2.NumPositions != 1) { string errorMessage = "Pattern 2: Number of patterns matched is not equal to one"; VisionLogger.Log(LogType.Exception, "PatternMatcherManager", errorMessage); VisionNotifier.AddNotification(errorMessage); goto Fail; } EROIBW8 matcherEROI_1 = MatcherEROI.GetROI(0); float OriginalXPos_pattern1 = eMatcher1.GetPosition(0).CenterX + (matcherEROI_1.OrgX); float OriginalYPos_pattern1 = eMatcher1.GetPosition(0).CenterY + (matcherEROI_1.OrgY); float OriginalXPos_pattern2 = eMatcher2.GetPosition(0).CenterX + (matcherEROI_1.OrgX); float OriginalYPos_pattern2 = eMatcher2.GetPosition(0).CenterY + (matcherEROI_1.OrgY); float WaferCenterXPos = WaferCenterPoint.X; float WaferCenterYPos = WaferCenterPoint.Y; PointF p1 = new PointF(OriginalXPos_pattern1, OriginalYPos_pattern1); PointF p2 = new PointF(OriginalXPos_pattern2, OriginalYPos_pattern2); float PatternDefaultAngleOffset = (float)CalculateAngleBetween3Points.Execute( p1, p2, WaferCenterPoint, 0, true, patternOrientation); // Replace value PatternMatcherParameters_.OriginalXPos_pattern1 = OriginalXPos_pattern1; PatternMatcherParameters_.OriginalYPos_pattern1 = OriginalYPos_pattern1; PatternMatcherParameters_.OriginalXPos_pattern2 = OriginalXPos_pattern2; PatternMatcherParameters_.OriginalYPos_pattern2 = OriginalYPos_pattern2; PatternMatcherParameters_.WaferCenterXPos = WaferCenterXPos; PatternMatcherParameters_.WaferCenterYPos = WaferCenterYPos; PatternMatcherParameters_.DefaultAngleOffset = PatternDefaultAngleOffset; return(true); Fail: return(false); }
public static List <EuresysDoubleMatcherResults> CreateDoublePatternMatcherResults( EuresysDoublePatternMatcher matcher, List <EROIBW8> matcherEROIs, float originalXPos_Pattern1, float originalYPos_Pattern1, PointF centerPoint, double refTheta, WaferOrientation patternOrientation) { if (matcher == null) { throw new ArgumentNullException("matcher"); } if (matcherEROIs == null) { throw new ArgumentNullException("matcherEROIs"); } if (matcherEROIs.Count < 1) { throw new ArgumentException("matcherEROIs count cannot be less than one"); } if (!matcher.isPatternMatched_) { throw new ArgumentException("Pattern is not matched"); } if (matcher.EMatcher1.NumPositions < 1) { throw new ArgumentException("No occurance on EMatcher1"); } if (matcher.EMatcher2.NumPositions < 1) { throw new ArgumentException("No occurance on EMatcher2"); } if (matcher.EMatcher1.NumPositions != matcher.EMatcher2.NumPositions) { throw new ArgumentException("Occurance for EMatcher 1 and EMatcher 2 nota tally"); } List <EuresysDoubleMatcherResults> result_list = new List <EuresysDoubleMatcherResults>(); for (int i = 0; i < matcher.EMatcher1.NumPositions; i++) { EuresysDoubleMatcherResults result = new EuresysDoubleMatcherResults() { Angle1 = matcher.EMatcher1.GetPosition(i).Angle, ScaleX1 = matcher.EMatcher1.GetPosition(i).ScaleX, ScaleY1 = matcher.EMatcher1.GetPosition(i).ScaleY, //CenterX1 = matcher.EMatcher1.GetPosition(i).CenterX, //CenterY1 = matcher.EMatcher1.GetPosition(i).CenterY, CenterX1 = matcher.EMatcher1.GetPosition(i).CenterX + (float)(matcherEROIs[0].OrgX), CenterY1 = matcher.EMatcher1.GetPosition(i).CenterY + (float)(matcherEROIs[0].OrgY), Score1 = matcher.EMatcher1.GetPosition(i).Score, Angle2 = matcher.EMatcher2.GetPosition(i).Angle, ScaleX2 = matcher.EMatcher2.GetPosition(i).ScaleX, ScaleY2 = matcher.EMatcher2.GetPosition(i).ScaleY, //CenterX2 = matcher.EMatcher2.GetPosition(i).CenterX, //CenterY2 = matcher.EMatcher2.GetPosition(i).CenterY, CenterX2 = matcher.EMatcher2.GetPosition(i).CenterX + (float)(matcherEROIs[0].OrgX), CenterY2 = matcher.EMatcher2.GetPosition(i).CenterY + (float)(matcherEROIs[0].OrgY), Score2 = matcher.EMatcher2.GetPosition(i).Score, }; PointF p1 = new PointF(result.CenterX1, result.CenterY1); PointF p2 = new PointF(result.CenterX2, result.CenterY2); double angle = CalculateAngleBetween3Points.Execute(p1, p2, centerPoint, refTheta, true, patternOrientation); result.AngleBetweenResult = (float)angle; result.XOffset = originalXPos_Pattern1 - result.CenterX1; result.YOffset = originalYPos_Pattern1 - result.CenterY1; result_list.Add(result); } return(result_list); }