public override System.Drawing.Point GetNextPointOnXAxis(ImageInstance theImage, ref System.Drawing.Point theNextPoint) { if (!mCompletedFirstROI) { // first iterate through the FirstROI blindly mFirstROI.GetNextPointOnXAxis(theImage, ref theNextPoint); if (theNextPoint.X != -1 && theNextPoint.Y != -1) { return(theNextPoint); } // once we hit the end of FirstROI, check if the first point in SecondROI is outside of FirstROI, if so, use it mCompletedFirstROI = true; theNextPoint = mSecondROI.GetFirstPointOnXAxis(theImage, ref theNextPoint); if (!mFirstROI.ContainsPoint(theImage, theNextPoint)) { return(theNextPoint); } } // after using up FirstROI and the first point of SecondROI, then iterate through SecondROI and weed out any duplicate point do { mSecondROI.GetNextPointOnXAxis(theImage, ref theNextPoint); } while (theNextPoint.X != -1 && theNextPoint.Y != -1 && mFirstROI.ContainsPoint(theImage, theNextPoint)); return(theNextPoint); }
public override System.Drawing.Point GetFirstPointOnXAxis(ImageInstance theImage, ref System.Drawing.Point theFirstPoint) { mMainROI.GetFirstPointOnXAxis(theImage, ref theFirstPoint); while (theFirstPoint.X != -1 && theFirstPoint.Y != -1 && mHoleROI.ContainsPoint(theImage, theFirstPoint)) { mMainROI.GetNextPointOnXAxis(theImage, ref theFirstPoint); } return(theFirstPoint); }
public override System.Drawing.Point GetFirstPointOnXAxis(ImageInstance theImage, ref System.Drawing.Point theFirstPoint) { mMainROI.GetFirstPointOnXAxis(theImage, ref theFirstPoint); while (theFirstPoint.X != -1 && theFirstPoint.Y != -1 && mColorException.Matches(theImage.GetColor(theFirstPoint.X, theFirstPoint.Y))) { mMainROI.GetNextPointOnXAxis(theImage, ref theFirstPoint); } return(theFirstPoint); }
public override void DoWork() { TestExecution().LogMessageWithTimeFromTrigger(Name + " started"); Stopwatch watch = new Stopwatch(); watch.Start(); long numPixels = 0; int H_current; double H_avg = -1; int H_min = 999999; int H_max = -999999; double H_stddev = -1; long H_sum = 0; int S_current; double S_avg = -1; int S_min = 999999; int S_max = -999999; double S_stddev = -1; long S_sum = 0; int I_current; double I_avg = -1; int I_min = 999999; int I_max = -999999; double I_stddev = -1; long I_sum = 0; int R_current; double R_avg = -1; int R_min = 999999; int R_max = -999999; double R_stddev = -1; long R_sum = 0; int G_current; double G_avg = -1; int G_min = 999999; int G_max = -999999; double G_stddev = -1; long G_sum = 0; int B_current; double B_avg = -1; int B_min = 999999; int B_max = -999999; double B_stddev = -1; long B_sum = 0; int Grey_current; double Grey_avg = -1; int Grey_min = 999999; int Grey_max = -999999; double Grey_stddev = -1; long Grey_sum = 0; if (mPrerequisite != null && !mPrerequisite.ValueAsBoolean()) { TestExecution().LogMessageWithTimeFromTrigger(Name + ": prerequisites not met. Skipping."); } else { if (true) { if (mSourceImage != null && mSourceImage.Bitmap != null) { Point currentPoint = new Point(-1, -1); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); Color color; while (currentPoint.X > -1 && currentPoint.Y > -1) { numPixels++; color = mSourceImage.GetColor(currentPoint.X, currentPoint.Y); H_current = (int)(color.GetHue()); S_current = (int)(color.GetSaturation() * 100); I_current = (int)(color.GetBrightness() * 100); Grey_current = (int)(0.3 * color.R + 0.59 * color.G + 0.11 * color.B); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). R_current = color.R; G_current = color.G; B_current = color.B; H_sum += H_current; if (H_current < H_min) { H_min = H_current; } if (H_current > H_max) { H_max = H_current; } S_sum += S_current; if (S_current < S_min) { S_min = S_current; } if (S_current > S_max) { S_max = S_current; } I_sum += I_current; if (I_current < I_min) { I_min = I_current; } if (I_current > I_max) { I_max = I_current; } R_sum += R_current; if (R_current < R_min) { R_min = R_current; } if (R_current > R_max) { R_max = R_current; } G_sum += G_current; if (G_current < G_min) { G_min = G_current; } if (G_current > G_max) { G_max = G_current; } B_sum += B_current; if (B_current < B_min) { B_min = B_current; } if (B_current > B_max) { B_max = B_current; } Grey_sum += Grey_current; if (Grey_current < Grey_min) { Grey_min = Grey_current; } if (Grey_current > Grey_max) { Grey_max = Grey_current; } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } if (numPixels > 0) { H_avg = ((double)H_sum) / numPixels; S_avg = ((double)S_sum) / numPixels; I_avg = ((double)I_sum) / numPixels; R_avg = ((double)R_sum) / numPixels; G_avg = ((double)G_sum) / numPixels; B_avg = ((double)B_sum) / numPixels; Grey_avg = ((double)Grey_sum) / numPixels; } else { TestExecution().LogErrorWithTimeFromTrigger("ColorAnalysis " + Name + " didn't analyze any pixels -- check ROI size."); } } // if image not null } else // if not new array pixel access, then use old pointer access { Bitmap sourceBitmap = SourceImage.Bitmap; if (sourceBitmap != null) { // for LockBits see http://www.bobpowell.net/lockingbits.htm & http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 BitmapData sourceBitmapData = null; try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); const int pixelByteWidth = 4; // determined by PixelFormat.Format32bppArgb int stride = sourceBitmapData.Stride; int strideOffset = stride - (sourceBitmapData.Width * pixelByteWidth); Point currentPoint = new Point(-1, -1); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; Color color; while (currentPoint.X > -1 && currentPoint.Y > -1) { numPixels++; sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha H_current = (int)(color.GetHue()); S_current = (int)(color.GetSaturation() * 100); I_current = (int)(color.GetBrightness() * 100); Grey_current = (int)(0.3 * color.R + 0.59 * color.G + 0.11 * color.B); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). R_current = color.R; G_current = color.G; B_current = color.B; H_sum += H_current; if (H_current < H_min) { H_min = H_current; } if (H_current > H_max) { H_max = H_current; } S_sum += S_current; if (S_current < S_min) { S_min = S_current; } if (S_current > S_max) { S_max = S_current; } I_sum += I_current; if (I_current < I_min) { I_min = I_current; } if (I_current > I_max) { I_max = I_current; } R_sum += R_current; if (R_current < R_min) { R_min = R_current; } if (R_current > R_max) { R_max = R_current; } G_sum += G_current; if (G_current < G_min) { G_min = G_current; } if (G_current > G_max) { G_max = G_current; } B_sum += B_current; if (B_current < B_min) { B_min = B_current; } if (B_current > B_max) { B_max = B_current; } Grey_sum += Grey_current; if (Grey_current < Grey_min) { Grey_min = Grey_current; } if (Grey_current > Grey_max) { Grey_max = Grey_current; } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } if (numPixels > 0) { H_avg = ((double)H_sum) / numPixels; S_avg = ((double)S_sum) / numPixels; I_avg = ((double)I_sum) / numPixels; R_avg = ((double)R_sum) / numPixels; G_avg = ((double)G_sum) / numPixels; B_avg = ((double)B_sum) / numPixels; Grey_avg = ((double)Grey_sum) / numPixels; } else { TestExecution().LogErrorWithTimeFromTrigger("ColorAnalysis " + Name + " didn't analyze any pixels -- check ROI size."); } } // end unsafe block } finally { sourceBitmap.UnlockBits(sourceBitmapData); } } // if bitmap } // pixel access type } // if prereqs met if (mH_Average != null) { mH_Average.SetValue(H_avg); mH_Average.SetIsComplete(); } if (mH_Min != null) { mH_Min.SetValue(H_min); mH_Min.SetIsComplete(); } if (mH_Max != null) { mH_Max.SetValue(H_max); mH_Max.SetIsComplete(); } if (mH_StdDev != null) { mH_StdDev.SetValue(H_stddev); mH_StdDev.SetIsComplete(); } if (mS_Average != null) { mS_Average.SetValue(S_avg); mS_Average.SetIsComplete(); } if (mS_Min != null) { mS_Min.SetValue(S_min); mS_Min.SetIsComplete(); } if (mS_Max != null) { mS_Max.SetValue(S_max); mS_Max.SetIsComplete(); } if (mS_StdDev != null) { mS_StdDev.SetValue(S_stddev); mS_StdDev.SetIsComplete(); } if (mI_Average != null) { mI_Average.SetValue(I_avg); mI_Average.SetIsComplete(); } if (mI_Min != null) { mI_Min.SetValue(I_min); mI_Min.SetIsComplete(); } if (mI_Max != null) { mI_Max.SetValue(I_max); mI_Max.SetIsComplete(); } if (mI_StdDev != null) { mI_StdDev.SetValue(I_stddev); mI_StdDev.SetIsComplete(); } if (mR_Average != null) { mR_Average.SetValue(R_avg); mR_Average.SetIsComplete(); } if (mR_Min != null) { mR_Min.SetValue(R_min); mR_Min.SetIsComplete(); } if (mR_Max != null) { mR_Max.SetValue(R_max); mR_Max.SetIsComplete(); } if (mR_StdDev != null) { mR_StdDev.SetValue(R_stddev); mR_StdDev.SetIsComplete(); } if (mG_Average != null) { mG_Average.SetValue(G_avg); mG_Average.SetIsComplete(); } if (mG_Min != null) { mG_Min.SetValue(G_min); mG_Min.SetIsComplete(); } if (mG_Max != null) { mG_Max.SetValue(G_max); mG_Max.SetIsComplete(); } if (mG_StdDev != null) { mG_StdDev.SetValue(G_stddev); mG_StdDev.SetIsComplete(); } if (mB_Average != null) { mB_Average.SetValue(B_avg); mB_Average.SetIsComplete(); } if (mB_Min != null) { mB_Min.SetValue(B_min); mB_Min.SetIsComplete(); } if (mB_Max != null) { mB_Max.SetValue(B_max); mB_Max.SetIsComplete(); } if (mB_StdDev != null) { mB_StdDev.SetValue(B_stddev); mB_StdDev.SetIsComplete(); } if (mGrey_Average != null) { mGrey_Average.SetValue(Grey_avg); mGrey_Average.SetIsComplete(); } if (mGrey_Min != null) { mGrey_Min.SetValue(Grey_min); mGrey_Min.SetIsComplete(); } if (mGrey_Max != null) { mGrey_Max.SetValue(Grey_max); mGrey_Max.SetIsComplete(); } if (mGrey_StdDev != null) { mGrey_StdDev.SetValue(Grey_stddev); mGrey_StdDev.SetIsComplete(); } mIsComplete = true; watch.Stop(); TestExecution().LogMessageWithTimeFromTrigger(Name + " took " + watch.ElapsedMilliseconds + "ms (" + watch.ElapsedTicks + " ticks for " + numPixels + " pixels)"); }
// public const string AnalysisType = "Color Present Fails"; // public override string Type() { return AnalysisType; } public override void DoWork() { TestExecution().LogMessageWithTimeFromTrigger("ColorMatchCount " + Name + " started"); DateTime startTime = DateTime.Now; mMatchCount = 0; if (mSourceImage.Bitmap != null) { if (true) { Point currentPoint = new Point(-1, -1); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); Color color; while (currentPoint.X != -1 && currentPoint.Y != -1) { color = mSourceImage.GetColor(currentPoint.X, currentPoint.Y); if (mColorMatcher.Matches(color)) { mMatchCount++; if (mImageToMark != null && mImageToMark.Bitmap != null) { mImageToMark.SetColor(currentPoint.X, currentPoint.Y, mMarkColor); } } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } } else { Bitmap sourceBitmap = SourceImage.Bitmap; Bitmap markedBitmap = null; if (mCreateMarkedImage && mImageToMark != null && mImageToMark.Bitmap != null) { markedBitmap = mImageToMark.Bitmap; } // for LockBits see http://www.bobpowell.net/lockingbits.htm & http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 BitmapData sourceBitmapData = null; BitmapData markedBitmapData = null; try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); if (markedBitmap != null) { markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } const int pixelByteWidth = 4; // determined by PixelFormat.Format32bppArgb int stride = sourceBitmapData.Stride; int strideOffset = stride - (sourceBitmapData.Width * pixelByteWidth); Point currentPoint = new Point(-1, -1); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; byte *markedPointer; Color color; while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha if (mColorMatcher.Matches(color)) { mMatchCount++; if (markedBitmap != null) { markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); markedPointer[3] = mMarkColor.A; markedPointer[2] = mMarkColor.R; markedPointer[1] = mMarkColor.G; markedPointer[0] = mMarkColor.B; } } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } } // end unsafe block } finally { sourceBitmap.UnlockBits(sourceBitmapData); if (markedBitmap != null) { markedBitmap.UnlockBits(markedBitmapData); } } } } mResult.SetValue(mMatchCount); mResult.SetIsComplete(); DateTime doneTime = DateTime.Now; TimeSpan computeTime = doneTime - startTime; TestExecution().LogMessageWithTimeFromTrigger(Name + " took " + computeTime.TotalMilliseconds + "ms"); //MessageBox.Show("done in color count for " + Name); }
public override System.Drawing.Point GetFirstPointOnXAxis(ImageInstance theImage, ref System.Drawing.Point theFirstPoint) { mCompletedFirstROI = false; mFirstROI.GetFirstPointOnXAxis(theImage, ref theFirstPoint); return(theFirstPoint); }
// public const string AnalysisType = "Color Present Fails"; // public override string Type() { return AnalysisType; } public override void DoWork() { //if (!mSourceImage.IsComplete() || !AreExplicitDependenciesComplete()) return; TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " started"); Bitmap sourceBitmap = SourceImage.Bitmap; Bitmap markedBitmap = null; if (mMarkedImage != null && sourceBitmap != null) { mMarkedImage.SetImage(new Bitmap(sourceBitmap)); markedBitmap = mMarkedImage.Bitmap; TestExecution().LogMessageWithTimeFromTrigger("Created copy of image for markings"); } long resultValue = 0; if (sourceBitmap != null) { // for LockBits see http://www.bobpowell.net/lockingbits.htm & http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 BitmapData sourceBitmapData = null; BitmapData markedBitmapData = null; try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); if (markedBitmap != null) { markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } const int pixelByteWidth = 4; // determined by PixelFormat.Format32bppArgb int stride = sourceBitmapData.Stride; int strideOffset = stride - (sourceBitmapData.Width * pixelByteWidth); Color color; int pixel1Intensity; int pixel2Intensity; long variation = 0; long threshhold = mVariationThreshhold.ValueAsLong(); Point lastPoint = new Point(-1, -1); Point currentPoint = new Point(-1, -1); if (mTestXAxis) { TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " testing X Axis"); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; byte *markedPointer; sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha pixel1Intensity = (int)(color.GetBrightness() * 100); lastPoint.X = currentPoint.X; lastPoint.Y = currentPoint.Y; mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha pixel2Intensity = (int)(color.GetBrightness() * 100); if (currentPoint.Y == lastPoint.Y) { variation = Math.Abs(pixel2Intensity - pixel1Intensity); if (variation > threshhold) { resultValue += variation; if (mMarkedImage != null) { markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); markedPointer[3] = mMarkColor.A; markedPointer[2] = mMarkColor.R; markedPointer[1] = mMarkColor.G; markedPointer[0] = mMarkColor.B; } } } pixel1Intensity = pixel2Intensity; lastPoint.X = currentPoint.X; lastPoint.Y = currentPoint.Y; mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } } // end unsafe block } if (mTestYAxis) { TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " testing Y Axis"); mROI.GetFirstPointOnYAxis(mSourceImage, ref currentPoint); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; byte *markedPointer; sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha pixel1Intensity = (int)(color.GetBrightness() * 100); lastPoint.X = currentPoint.X; lastPoint.Y = currentPoint.Y; mROI.GetNextPointOnYAxis(mSourceImage, ref currentPoint); while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha pixel2Intensity = (int)(color.GetBrightness() * 100); if (currentPoint.X == lastPoint.X) { variation = Math.Abs(pixel2Intensity - pixel1Intensity); if (variation > threshhold) { resultValue += variation; if (mMarkedImage != null) { markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * stride) + (currentPoint.X * pixelByteWidth); markedPointer[3] = mMarkColor.A; markedPointer[2] = mMarkColor.R; markedPointer[1] = mMarkColor.G; markedPointer[0] = mMarkColor.B; } } } pixel1Intensity = pixel2Intensity; lastPoint.X = currentPoint.X; lastPoint.Y = currentPoint.Y; mROI.GetNextPointOnYAxis(mSourceImage, ref currentPoint); } } // end unsafe block } } finally { sourceBitmap.UnlockBits(sourceBitmapData); if (markedBitmap != null) { markedBitmap.UnlockBits(markedBitmapData); } } } mResult.SetValue(resultValue); mResult.SetIsComplete(); if (mMarkedImage != null) { mMarkedImage.SetIsComplete(); } TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " completed"); }
// public const string AnalysisType = "Color Present Fails"; // public override string Type() { return AnalysisType; } public override void DoWork() { TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " started"); /* * if (Definition(.ScoreFilter != null) * { * mScoreFilter = testExecution.GetScoreFilter(theDefinition.ScoreFilter.Name); * } */ Bitmap sourceBitmap = SourceImage.Bitmap; Bitmap markedBitmap = null; PatternMatchOfAvgGrayVariationDefinition theDef = (PatternMatchOfAvgGrayVariationDefinition)Definition(); if (theDef.mPatternAvgValues == null) { theDef.LoadPatterns(false); } Bitmap patternAvgValues = theDef.mPatternAvgValues; Bitmap patternStdDevValues = theDef.mPatternStdDevValues; Bitmap patternMinValues = theDef.mPatternMinValues; Bitmap patternMaxValues = theDef.mPatternMaxValues; if (patternAvgValues == null || patternStdDevValues == null || patternMinValues == null || patternMaxValues == null) { throw new ArgumentException("Pattern to match isn't defined."); } if (mMarkedImage != null && sourceBitmap != null) { mMarkedImage.SetImage(new Bitmap(sourceBitmap)); markedBitmap = mMarkedImage.Bitmap; TestExecution().LogMessageWithTimeFromTrigger("Created copy of image for markings"); } long score = 0; if (sourceBitmap != null) { // for LockBits see http://www.bobpowell.net/lockingbits.htm & http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 BitmapData sourceBitmapData = null; BitmapData markedBitmapData = null; BitmapData patternAvgValuesBitmapData = null; BitmapData patternStdDevValuesBitmapData = null; BitmapData patternMinValuesBitmapData = null; BitmapData patternMaxValuesBitmapData = null; if (mScoreFilter != null) { mScoreFilter.SetImageSize(mSourceImage.Bitmap.Width, mSourceImage.Bitmap.Height); } try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PatternMatchOfAvgGrayVariationDefinition.TRAINING_PIXEL_FORMAT); patternAvgValuesBitmapData = patternAvgValues.LockBits(new Rectangle(0, 0, patternAvgValues.Width, patternAvgValues.Height), ImageLockMode.ReadOnly, PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternStdDevValuesBitmapData = patternStdDevValues.LockBits(new Rectangle(0, 0, patternStdDevValues.Width, patternStdDevValues.Height), ImageLockMode.ReadOnly, PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMinValuesBitmapData = patternMinValues.LockBits(new Rectangle(0, 0, patternMinValues.Width, patternMinValues.Height), ImageLockMode.ReadOnly, PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMaxValuesBitmapData = patternMaxValues.LockBits(new Rectangle(0, 0, patternMaxValues.Width, patternMaxValues.Height), ImageLockMode.ReadOnly, PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_FORMAT); if (markedBitmap != null) { markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } int sourceStride = sourceBitmapData.Stride; int sourceStrideOffset = sourceStride - (sourceBitmapData.Width * PatternMatchOfAvgGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); int patternStride = patternAvgValuesBitmapData.Stride; int patternStrideOffset = patternStride - (patternAvgValuesBitmapData.Width * PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); int grayValue; int grayValue2; long variation = 0; long patternWindow = 0; long threshhold = mVariationThreshhold.ValueAsLong(); double sloppiness = mSloppiness.ValueAsDecimal() / 100.0; long minWindow = Math.Max(1, mMinWindow.ValueAsLong()); double brightPixelFactor = mBrightPixelFactor.ValueAsDecimal(); double darkPixelFactor = mDarkPixelFactor.ValueAsDecimal(); bool needToMark = false; long scoreChange = 0; int testPixelVariation; int minVarForThisPixel; int maxVarForThisPixel; Point currentPoint = new Point(-1, -1); TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " testing X Axis"); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; byte *sourcePointer2; byte *markedPointer; byte *patternAvgValuesPointer; byte *patternStdDevValuesPointer; byte *patternMinValuesPointer; byte *patternMaxValuesPointer; while (currentPoint.X != -1 && currentPoint.Y != -1) { scoreChange = -999; variation = -999; sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); // adjust to current point grayValue = (int)(0.3 * sourcePointer[2] + 0.59 * sourcePointer[1] + 0.11 * sourcePointer[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). // http://www.bobpowell.net/grayscale.htm // https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=440425&SiteID=1 // check pixel above sourcePointer2 = sourcePointer - sourceStride; grayValue2 = (int)(0.3 * sourcePointer2[2] + 0.59 * sourcePointer2[1] + 0.11 * sourcePointer2[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). testPixelVariation = grayValue - grayValue2; // NOTE: using '=' to init varSum for this pixel testPixelVariation = Math.Max(-127, Math.Min(128, testPixelVariation)); // make sure we stay within 1 byte (0..255) patternAvgValuesPointer = (byte *)patternAvgValuesBitmapData.Scan0; // init to first byte of image patternAvgValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point patternStdDevValuesPointer = (byte *)patternStdDevValuesBitmapData.Scan0; // init to first byte of image patternStdDevValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point patternMinValuesPointer = (byte *)patternMinValuesBitmapData.Scan0; // init to first byte of image patternMinValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point minVarForThisPixel = patternMinValuesPointer[0] - 127; patternMaxValuesPointer = (byte *)patternMaxValuesBitmapData.Scan0; // init to first byte of image patternMaxValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point maxVarForThisPixel = patternMaxValuesPointer[0] - 127; patternWindow = maxVarForThisPixel - minVarForThisPixel; // give tight windows more weight in the score patternWindow = Math.Max(minWindow, patternWindow); // ensure minWindow>0 to prevent divideBy0 if (patternWindow > threshhold) { scoreChange = 0; markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); markedPointer[3] = Color.Yellow.A; markedPointer[2] = Color.Yellow.R; markedPointer[1] = Color.Yellow.G; markedPointer[0] = Color.Yellow.B; } else { if (testPixelVariation < minVarForThisPixel - sloppiness * patternWindow) { variation = minVarForThisPixel - testPixelVariation; //scoreChange = (long)(((variation / patternWindow) + 1) * darkPixelFactor); scoreChange = (long)(variation * ((variation / (patternWindow / 2)) + 1) * darkPixelFactor); score += scoreChange; needToMark = true; TestExecution().LogMessage("Pattern Match score event: " + currentPoint.X + "," + currentPoint.Y + " dark spot score=" + scoreChange + " var=" + testPixelVariation + " min=" + minVarForThisPixel + " max=" + maxVarForThisPixel + " window=" + patternWindow + " var=" + variation); if (mScoreFilter != null) { mScoreFilter.ProcessScore(currentPoint.X, currentPoint.Y, scoreChange); } } else if (testPixelVariation > maxVarForThisPixel + sloppiness * patternWindow) { variation = testPixelVariation - maxVarForThisPixel; //scoreChange = (long)(((variation / patternWindow) + 1) * brightPixelFactor); scoreChange = (long)(variation * ((variation / (patternWindow / 2)) + 1) * brightPixelFactor); score += scoreChange; needToMark = true; TestExecution().LogMessage("Pattern Match score event: " + currentPoint.X + "," + currentPoint.Y + " bright spot score=" + scoreChange + " var=" + testPixelVariation + " min=" + minVarForThisPixel + " max=" + maxVarForThisPixel + " window=" + patternWindow + " var=" + variation); if (mScoreFilter != null) { mScoreFilter.ProcessScore(currentPoint.X, currentPoint.Y, scoreChange); } } else { variation = 0; scoreChange = 0; needToMark = false; } if (needToMark && mMarkedImage != null) { markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfAvgGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); markedPointer[3] = mMarkColor.A; markedPointer[2] = mMarkColor.R; markedPointer[1] = mMarkColor.G; markedPointer[0] = mMarkColor.B; } } if (mDeepAnalysisEnabled && currentPoint.X >= mDeepAnalysisLeft && currentPoint.X <= mDeepAnalysisRight && currentPoint.Y >= mDeepAnalysisTop && currentPoint.Y <= mDeepAnalysisBottom) { string message = "DEEP ANALYSIS: '" + Name + "' " + currentPoint.X + "," + currentPoint.Y + " "; if (patternWindow > threshhold) { message += "PATTERN WINDOW > THRESHOLD;"; } message += " score change=" + scoreChange + " var=" + testPixelVariation + " min=" + minVarForThisPixel + " max=" + maxVarForThisPixel + " window=" + patternWindow + " slop=" + (sloppiness * patternWindow) + " marked=" + needToMark ; TestExecution().LogMessage(message); } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } } // end unsafe block } finally { sourceBitmap.UnlockBits(sourceBitmapData); patternAvgValues.UnlockBits(patternAvgValuesBitmapData); patternStdDevValues.UnlockBits(patternStdDevValuesBitmapData); patternMinValues.UnlockBits(patternMinValuesBitmapData); patternMaxValues.UnlockBits(patternMaxValuesBitmapData); if (markedBitmap != null) { markedBitmap.UnlockBits(markedBitmapData); } } } mResult.SetValue(score); mResult.SetIsComplete(); if (mMarkedImage != null) { mMarkedImage.SetIsComplete(); } TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " completed; score=" + score); }
// public const string AnalysisType = "Color Present Fails"; // public override string Type() { return AnalysisType; } public override void DoWork() { TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " started"); Bitmap sourceBitmap = SourceImage.Bitmap; Bitmap markedBitmap = null; PatternMatchOfGrayValueDefinition theDef = (PatternMatchOfGrayValueDefinition)Definition(); if (theDef.mPatternMinValues == null || theDef.mPatternMaxValues == null) { theDef.LoadPatterns(false); } Bitmap patternMinValues = theDef.mPatternMinValues; Bitmap patternMaxValues = theDef.mPatternMaxValues; if (patternMinValues == null || patternMaxValues == null) { throw new ArgumentException("Pattern to match isn't defined."); } if (mMarkedImage != null && sourceBitmap != null) { mMarkedImage.SetImage(new Bitmap(sourceBitmap)); markedBitmap = mMarkedImage.Bitmap; TestExecution().LogMessageWithTimeFromTrigger("Created copy of image for markings"); } long score = 0; if (sourceBitmap != null) { // for LockBits see http://www.bobpowell.net/lockingbits.htm & http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 BitmapData sourceBitmapData = null; BitmapData markedBitmapData = null; BitmapData patternMinValuesBitmapData = null; BitmapData patternMaxValuesBitmapData = null; try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayValueDefinition.TRAINING_PIXEL_FORMAT); patternMinValuesBitmapData = patternMinValues.LockBits(new Rectangle(0, 0, patternMinValues.Width, patternMinValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayValueDefinition.PATTERN_PIXEL_FORMAT); patternMaxValuesBitmapData = patternMaxValues.LockBits(new Rectangle(0, 0, patternMaxValues.Width, patternMaxValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayValueDefinition.PATTERN_PIXEL_FORMAT); if (markedBitmap != null) { markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } int sourceStride = sourceBitmapData.Stride; int sourceStrideOffset = sourceStride - (sourceBitmapData.Width * PatternMatchOfGrayValueDefinition.TRAINING_PIXEL_BYTE_WIDTH); int patternStride = patternMinValuesBitmapData.Stride; int patternStrideOffset = patternStride - (patternMinValuesBitmapData.Width * PatternMatchOfGrayValueDefinition.PATTERN_PIXEL_BYTE_WIDTH); Color color; int grayValue; long variation = 0; long patternWindow = 0; long threshhold = mVariationThreshhold.ValueAsLong(); double sloppiness = mSloppiness.ValueAsDecimal() / 100.0; long minWindow = Math.Max(1, mMinWindow.ValueAsLong()); double brightPixelFactor = mBrightPixelFactor.ValueAsDecimal(); double darkPixelFactor = mDarkPixelFactor.ValueAsDecimal(); bool needToMark = false; long scoreChange = 0; Point currentPoint = new Point(-1, -1); TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " testing X Axis"); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; byte *markedPointer; byte *patternMinValuesPointer; byte *patternMaxValuesPointer; while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfGrayValueDefinition.TRAINING_PIXEL_BYTE_WIDTH); // adjust to current point color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha grayValue = (int)(0.3 * color.R + 0.59 * color.G + 0.11 * color.B); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). // http://www.bobpowell.net/grayscale.htm // https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=440425&SiteID=1 patternMinValuesPointer = (byte *)patternMinValuesBitmapData.Scan0; // init to first byte of image patternMinValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfGrayValueDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point patternMaxValuesPointer = (byte *)patternMaxValuesBitmapData.Scan0; // init to first byte of image patternMaxValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfGrayValueDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point patternWindow = patternMaxValuesPointer[0] - patternMinValuesPointer[0]; // give tight windows more weight in the score patternWindow = Math.Max(minWindow, patternWindow); // ensure minWindow>0 to prevent divideBy0 if (patternWindow > threshhold) { markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfGrayValueDefinition.TRAINING_PIXEL_BYTE_WIDTH); markedPointer[3] = Color.Yellow.A; markedPointer[2] = Color.Yellow.R; markedPointer[1] = Color.Yellow.G; markedPointer[0] = Color.Yellow.B; } else { if (grayValue < patternMinValuesPointer[0] - sloppiness * patternWindow) { variation = patternMinValuesPointer[0] - grayValue; //scoreChange = (long)(((variation / patternWindow) + 1) * darkPixelFactor); scoreChange = (long)(variation * ((variation / (patternWindow / 2)) + 1) * darkPixelFactor); score += scoreChange; needToMark = true; TestExecution().LogMessage("Pattern Match score event: " + currentPoint.X + "," + currentPoint.Y + " dark spot score=" + scoreChange + " gray=" + grayValue + " min=" + patternMinValuesPointer[0] + " max=" + patternMaxValuesPointer[0] + " window=" + patternWindow + " var=" + variation); } else if (grayValue > patternMaxValuesPointer[0] + sloppiness * patternWindow) { variation = grayValue - patternMaxValuesPointer[0]; //scoreChange = (long)(((variation / patternWindow) + 1) * brightPixelFactor); scoreChange = (long)(variation * ((variation / (patternWindow / 2)) + 1) * brightPixelFactor); score += scoreChange; needToMark = true; TestExecution().LogMessage("Pattern Match score event: " + currentPoint.X + "," + currentPoint.Y + " bright spot score=" + scoreChange + " gray=" + grayValue + " min=" + patternMinValuesPointer[0] + " max=" + patternMaxValuesPointer[0] + " window=" + patternWindow + " var=" + variation); } else { needToMark = false; } if (needToMark && mMarkedImage != null) { markedPointer = (byte *)markedBitmapData.Scan0; markedPointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfGrayValueDefinition.TRAINING_PIXEL_BYTE_WIDTH); markedPointer[3] = mMarkColor.A; markedPointer[2] = mMarkColor.R; markedPointer[1] = mMarkColor.G; markedPointer[0] = mMarkColor.B; } } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } } // end unsafe block } finally { sourceBitmap.UnlockBits(sourceBitmapData); patternMinValues.UnlockBits(patternMinValuesBitmapData); patternMaxValues.UnlockBits(patternMaxValuesBitmapData); if (markedBitmap != null) { markedBitmap.UnlockBits(markedBitmapData); } } } mResult.SetValue(score); mResult.SetIsComplete(); if (mMarkedImage != null) { mMarkedImage.SetIsComplete(); } TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " completed; score=" + score); }
public static readonly int PIXEL_BYTE_WIDTH = 4; // determined by PixelFormat.Format32bppArgb; http://www.bobpowell.net/lockingbits.htm public override void DoWork() { /* TODO: OPTIMIZATIONS: * - compute surfaceNoiseLevel based on image analysis * - make debug output to log optional * - surface/transition decorations (biggest problem is that there can be a variable number...only for first edge to start?) * - for marked image, save decorations...don't copy/paint_on image */ DateTime startTime = DateTime.Now; TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine); int resultX = -1; int resultY = -1; if (mSourceImage.Bitmap == null) { TestExecution().LogMessage("ERROR: source image for '" + Name + "' does not exist."); } else { Bitmap sourceBitmap = SourceImage.Bitmap; BitmapData sourceBitmapData = null; try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PIXEL_FORMAT); int sourceStride = sourceBitmapData.Stride; int sourceStrideOffset = sourceStride - (sourceBitmapData.Width * PIXEL_BYTE_WIDTH); int brightnessThreshold = (int)mBrightnessThreshold.ValueAsLong(); Point currentPoint = new Point(-1, -1); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); ValueGrouper xGrouper = new ValueGrouper(0, 255, 50); ValueGrouper yGrouper = new ValueGrouper(0, 255, 50); unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PIXEL_BYTE_WIDTH); // adjust to current point pixelGrayValue = (int)(0.3 * sourcePointer[2] + 0.59 * sourcePointer[1] + 0.11 * sourcePointer[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). // http://www.bobpowell.net/grayscale.htm // https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=440425&SiteID=1 //TestExecution().LogMessage(currentPoint.X + "," + currentPoint.Y + " " + pixelGrayValue + " " + brightnessThreshold); if (pixelGrayValue >= brightnessThreshold) { xGrouper.AddValue(currentPoint.X); yGrouper.AddValue(currentPoint.Y); } mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] finished analyzing pixels"); } // end unsafe block for (int z = 0; z < xGrouper.NumGroups; z++) { ValueGrouper.GroupStats groupStats = xGrouper.GetGroup(z); TestExecution().LogMessage(groupStats.start + " " + groupStats.end + " " + groupStats.count + " " + groupStats.Average()); } for (int z = 0; z < yGrouper.NumGroups; z++) { ValueGrouper.GroupStats groupStats = yGrouper.GetGroup(z); TestExecution().LogMessage(groupStats.start + " " + groupStats.end + " " + groupStats.count + " " + groupStats.Average()); } ValueGrouper.GroupStats biggestXGroup = xGrouper.BiggestGroupWithNeighbors(); if (biggestXGroup != null) { resultX = biggestXGroup.Average(); } ValueGrouper.GroupStats biggestYGroup = yGrouper.BiggestGroupWithNeighbors(); if (biggestXGroup != null) { resultY = biggestYGroup.Average(); } } catch (Exception e) { TestExecution().LogMessageWithTimeFromTrigger("ERROR: Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace); } finally { sourceBitmap.UnlockBits(sourceBitmapData); } } // end main block ("else" after all initial setup error checks) mBrightSpot_X.SetValue(resultX); mBrightSpot_Y.SetValue(resultY); mBrightSpot_X.SetIsComplete(); mBrightSpot_Y.SetIsComplete(); DateTime doneTime = DateTime.Now; TimeSpan computeTime = doneTime - startTime; TestExecution().LogMessageWithTimeFromTrigger(Name + " computed bright spot at " + resultX + "," + resultY); if (mAutoSave) { try { string filePath = ((FindBrightestSpotDefinition)Definition()).AutoSavePath; mSourceImage.Save(filePath, Name, true); TestExecution().LogMessageWithTimeFromTrigger("Snapshot saved"); } catch (ArgumentException e) { Project().Window().logMessage("ERROR: " + e.Message); TestExecution().LogErrorWithTimeFromTrigger(e.Message); } catch (Exception e) { Project().Window().logMessage("ERROR: Unable to AutoSave snapshot from " + Name + ". Ensure path valid and disk not full. Low-level message=" + e.Message); TestExecution().LogErrorWithTimeFromTrigger("Unable to AutoSave snapshot from " + Name + ". Ensure path valid and disk not full."); } } TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + " | took " + computeTime.TotalMilliseconds + "ms"); }
public override void DoWork() { if (mCollectImages) { try { mSourceImage.Save(((PatternMatchOfGrayVariationDefinition)Definition()).LearningPath, Name, true); TestExecution().LogMessageWithTimeFromTrigger(Name + " collected image in learning folder. Skipping test."); } catch (ArgumentException e) { Project().Window().logMessage("ERROR: " + e.Message); TestExecution().LogErrorWithTimeFromTrigger(e.Message); } catch (Exception e) { string errMsg = "Unable to save collected image. Ensure path valid and disk not full."; Project().Window().logMessage("ERROR: " + errMsg + " Low-level message=" + e.Message); TestExecution().LogErrorWithTimeFromTrigger(errMsg); } mResult.SetValue(score); mResult.SetIsComplete(); return; } TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " started"); /* * if (Definition(.ScoreFilter != null) * { * mScoreFilter = testExecution.GetScoreFilter(theDefinition.ScoreFilter.Name); * } */ Bitmap sourceBitmap = SourceImage.Bitmap; Bitmap markedBitmap = null; PatternMatchOfGrayVariationDefinition theDef = (PatternMatchOfGrayVariationDefinition)Definition(); if (theDef.mPatternMinDownValues == null || theDef.mPatternMaxDownValues == null) { theDef.LoadPatterns(false); } Bitmap patternMinDownValues = theDef.mPatternMinDownValues; Bitmap patternMaxDownValues = theDef.mPatternMaxDownValues; Bitmap patternMinUpValues = theDef.mPatternMinUpValues; Bitmap patternMaxUpValues = theDef.mPatternMaxUpValues; Bitmap patternMinRightValues = theDef.mPatternMinRightValues; Bitmap patternMaxRightValues = theDef.mPatternMaxRightValues; Bitmap patternMinLeftValues = theDef.mPatternMinLeftValues; Bitmap patternMaxLeftValues = theDef.mPatternMaxLeftValues; if (patternMinDownValues == null || patternMaxDownValues == null) { throw new ArgumentException("Pattern to match isn't defined."); } if (mMarkedImage != null && sourceBitmap != null) { mMarkedImage.SetImage(new Bitmap(sourceBitmap)); markedBitmap = mMarkedImage.Bitmap; TestExecution().LogMessageWithTimeFromTrigger("Created copy of image for markings"); } score = 0; if (sourceBitmap != null) { // for LockBits see http://www.bobpowell.net/lockingbits.htm & http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 BitmapData sourceBitmapData = null; BitmapData patternMinDownValuesBitmapData = null; BitmapData patternMaxDownValuesBitmapData = null; BitmapData patternMinUpValuesBitmapData = null; BitmapData patternMaxUpValuesBitmapData = null; BitmapData patternMinRightValuesBitmapData = null; BitmapData patternMaxRightValuesBitmapData = null; BitmapData patternMinLeftValuesBitmapData = null; BitmapData patternMaxLeftValuesBitmapData = null; if (mScoreFilter != null) { mScoreFilter.SetImageSize(mSourceImage.Bitmap.Width, mSourceImage.Bitmap.Height); } try { sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.TRAINING_PIXEL_FORMAT); patternMinDownValuesBitmapData = patternMinDownValues.LockBits(new Rectangle(0, 0, patternMinDownValues.Width, patternMinDownValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMaxDownValuesBitmapData = patternMaxDownValues.LockBits(new Rectangle(0, 0, patternMaxDownValues.Width, patternMaxDownValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMinUpValuesBitmapData = patternMinUpValues.LockBits(new Rectangle(0, 0, patternMinUpValues.Width, patternMinUpValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMaxUpValuesBitmapData = patternMaxUpValues.LockBits(new Rectangle(0, 0, patternMaxUpValues.Width, patternMaxUpValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMinRightValuesBitmapData = patternMinRightValues.LockBits(new Rectangle(0, 0, patternMinRightValues.Width, patternMinRightValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMaxRightValuesBitmapData = patternMaxRightValues.LockBits(new Rectangle(0, 0, patternMaxRightValues.Width, patternMaxRightValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMinLeftValuesBitmapData = patternMinLeftValues.LockBits(new Rectangle(0, 0, patternMinLeftValues.Width, patternMinLeftValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); patternMaxLeftValuesBitmapData = patternMaxLeftValues.LockBits(new Rectangle(0, 0, patternMaxLeftValues.Width, patternMaxLeftValues.Height), ImageLockMode.ReadOnly, PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_FORMAT); if (markedBitmap != null) { markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } sourceStride = sourceBitmapData.Stride; int sourceStrideOffset = sourceStride - (sourceBitmapData.Width * PatternMatchOfGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); int patternStride = patternMinDownValuesBitmapData.Stride; int patternStrideOffset = patternStride - (patternMinDownValuesBitmapData.Width * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); //Color color; int grayValue; int grayValue2; threshhold = mVariationThreshhold.ValueAsLong(); sloppiness = mSloppiness.ValueAsDecimal() / 100.0; minWindow = Math.Max(1, mMinWindow.ValueAsLong()); scoreThreshold = mScoreThreshold.ValueAsLong(); brightPixelFactor = mBrightPixelFactor.ValueAsDecimal(); darkPixelFactor = mDarkPixelFactor.ValueAsDecimal(); int varSum; int minVarForThisPixel; int maxVarForThisPixel; Point currentPoint = new Point(-1, -1); int lastX = -1; int lastY = -1; int[] variationArray = new int[PatternMatchOfGrayVariationDefinition.PixelsPerTest]; int positionsUntested = 0; mFirstAxisScores = new long[sourceBitmap.Width, sourceBitmap.Height]; unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623 { byte *sourcePointer; byte *sourcePointer2; byte *patternMinValuesPointer; byte *patternMaxValuesPointer; TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " testing Y Axis"); mROI.GetFirstPointOnYAxis(mSourceImage, ref currentPoint); while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); // adjust to current point //color = Color.FromArgb(sourcePointer[3], , , ); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha grayValue = (int)(0.3 * sourcePointer[2] + 0.59 * sourcePointer[1] + 0.11 * sourcePointer[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). // http://www.bobpowell.net/grayscale.htm // https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=440425&SiteID=1 // check pixel above sourcePointer2 = sourcePointer - sourceStride; // TODO: ensure y>0 grayValue2 = (int)(0.3 * sourcePointer2[2] + 0.59 * sourcePointer2[1] + 0.11 * sourcePointer2[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). varSum = grayValue - grayValue2; // NOTE: using '=' to init varSum for this pixel if (currentPoint.X != lastX || currentPoint.Y != lastY + 1) { // init variationArray for (int i = 0; i < PatternMatchOfGrayVariationDefinition.PixelsPerTest; ++i) { variationArray[i] = PatternMatchOfGrayVariationDefinition.VALUE_NOT_DEFINED; } if (positionsUntested > 0) { // TODO: if this isn't 0, then mark untested pixels a certain color? // this should only happen when the ROI is less than PixelsPerTest high at a particular X value TestExecution().LogMessageWithTimeFromTrigger("WARNING: " + positionsUntested + " pixels were not tested above " + lastX + "," + lastY); } positionsUntested = 0; } // shift variationArray for (int i = 0; i < PatternMatchOfGrayVariationDefinition.PixelsPerTest - 1; ++i) { variationArray[i] = variationArray[i + 1]; } // store most recent value variationArray[PatternMatchOfGrayVariationDefinition.PixelsPerTest - 1] = varSum; if (variationArray[0] == PatternMatchOfGrayVariationDefinition.VALUE_NOT_DEFINED) { positionsUntested++; } else { int variationSum = 0; // compute sum variation over X pixel transitions for (int i = 0; i < PatternMatchOfGrayVariationDefinition.PixelsPerTest; ++i) { variationSum += variationArray[i]; } variationSum = Math.Max(-127, Math.Min(128, variationSum)); // make sure we stay within 1 byte (0..255) // test pixel patternMinValuesPointer = (byte *)patternMinDownValuesBitmapData.Scan0; // init to first byte of image patternMinValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point minVarForThisPixel = patternMinValuesPointer[0] - 127; patternMaxValuesPointer = (byte *)patternMaxDownValuesBitmapData.Scan0; // init to first byte of image patternMaxValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point maxVarForThisPixel = patternMaxValuesPointer[0] - 127; TestPixel(currentPoint.X, currentPoint.Y, variationSum, minVarForThisPixel, maxVarForThisPixel, true); if (positionsUntested > 0) { // if we missed testing a pixel above us (because it was near an ROI or image top edge where there weren't pixels above it to compute from), we test them here computing in the opposite direction (up values vs down values) // current pixel - PixelsPerTest = -variationSum int testPositionY = currentPoint.Y - PatternMatchOfGrayVariationDefinition.PixelsPerTest; if (testPositionY < 0) { throw new ArgumentException("Fatal logic error in test 93420rf"); } patternMinValuesPointer = (byte *)patternMinUpValuesBitmapData.Scan0; // init to first byte of image patternMinValuesPointer += (testPositionY * patternStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point minVarForThisPixel = patternMinValuesPointer[0] - 127; patternMaxValuesPointer = (byte *)patternMaxUpValuesBitmapData.Scan0; // init to first byte of image patternMaxValuesPointer += (testPositionY * patternStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point maxVarForThisPixel = patternMaxValuesPointer[0] - 127; TestPixel(currentPoint.X, testPositionY, -variationSum, minVarForThisPixel, maxVarForThisPixel, true); positionsUntested--; } } lastX = currentPoint.X; lastY = currentPoint.Y; mROI.GetNextPointOnYAxis(mSourceImage, ref currentPoint); } TestExecution().LogMessageWithTimeFromTrigger("PatternMatch " + Name + " testing X Axis"); mROI.GetFirstPointOnXAxis(mSourceImage, ref currentPoint); while (currentPoint.X != -1 && currentPoint.Y != -1) { sourcePointer = (byte *)sourceBitmapData.Scan0; // init to first byte of image sourcePointer += (currentPoint.Y * sourceStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH); // adjust to current point //color = Color.FromArgb(sourcePointer[3], sourcePointer[2], sourcePointer[1], sourcePointer[0]); // Array index 0 is blue, 1 is green, 2 is red, 0 is alpha grayValue = (int)(0.3 * sourcePointer[2] + 0.59 * sourcePointer[1] + 0.11 * sourcePointer[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). // http://www.bobpowell.net/grayscale.htm // https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=440425&SiteID=1 // check pixel behind sourcePointer2 = sourcePointer - PatternMatchOfGrayVariationDefinition.TRAINING_PIXEL_BYTE_WIDTH; // TODO: ensure y>0 grayValue2 = (int)(0.3 * sourcePointer2[2] + 0.59 * sourcePointer2[1] + 0.11 * sourcePointer2[0]); // Then, add 30% of the red value, 59% of the green value, and 11% of the blue value, together. .... These percentages are chosen due to the different relative sensitivity of the normal human eye to each of the primary colors (less sensitive to green, more to blue). varSum = grayValue - grayValue2; // NOTE: using '=' to init varSum for this pixel if (currentPoint.Y != lastY || currentPoint.X != lastX + 1) { // init variationArray for (int i = 0; i < PatternMatchOfGrayVariationDefinition.PixelsPerTest; ++i) { variationArray[i] = PatternMatchOfGrayVariationDefinition.VALUE_NOT_DEFINED; } if (positionsUntested > 0) { // TODO: if this isn't 0, then mark untested pixels a certain color? // this should only happen when the ROI is less than PixelsPerTest high at a particular X value TestExecution().LogMessageWithTimeFromTrigger("WARNING: " + positionsUntested + " pixels were not tested behind " + lastX + "," + lastY); } positionsUntested = 0; } // shift variationArray for (int i = 0; i < PatternMatchOfGrayVariationDefinition.PixelsPerTest - 1; ++i) { variationArray[i] = variationArray[i + 1]; } // store most recent value variationArray[PatternMatchOfGrayVariationDefinition.PixelsPerTest - 1] = varSum; if (variationArray[0] == PatternMatchOfGrayVariationDefinition.VALUE_NOT_DEFINED) { positionsUntested++; } else { int variationSum = 0; // compute sum variation over X pixel transitions for (int i = 0; i < PatternMatchOfGrayVariationDefinition.PixelsPerTest; ++i) { variationSum += variationArray[i]; } variationSum = Math.Max(-127, Math.Min(128, variationSum)); // make sure we stay within 1 byte (0..255) // test pixel patternMinValuesPointer = (byte *)patternMinDownValuesBitmapData.Scan0; // init to first byte of image patternMinValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point minVarForThisPixel = patternMinValuesPointer[0] - 127; patternMaxValuesPointer = (byte *)patternMaxDownValuesBitmapData.Scan0; // init to first byte of image patternMaxValuesPointer += (currentPoint.Y * patternStride) + (currentPoint.X * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point maxVarForThisPixel = patternMaxValuesPointer[0] - 127; TestPixel(currentPoint.X, currentPoint.Y, variationSum, minVarForThisPixel, maxVarForThisPixel, false); if (positionsUntested > 0) { // if we missed testing a pixel behind us (because it was near an ROI or image left edge where there weren't pixels behind it to compute from), we test them here computing in the opposite direction (left values vs right values) // current pixel - PixelsPerTest = -variationSum int testPositionX = currentPoint.X - PatternMatchOfGrayVariationDefinition.PixelsPerTest; if (testPositionX < 0) { throw new ArgumentException("Fatal logic error in test 93430rf"); } patternMinValuesPointer = (byte *)patternMinUpValuesBitmapData.Scan0; // init to first byte of image patternMinValuesPointer += (currentPoint.Y * patternStride) + (testPositionX * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point minVarForThisPixel = patternMinValuesPointer[0] - 127; patternMaxValuesPointer = (byte *)patternMaxUpValuesBitmapData.Scan0; // init to first byte of image patternMaxValuesPointer += (currentPoint.Y * patternStride) + (testPositionX * PatternMatchOfGrayVariationDefinition.PATTERN_PIXEL_BYTE_WIDTH); // adjust to current point maxVarForThisPixel = patternMaxValuesPointer[0] - 127; TestPixel(testPositionX, currentPoint.Y, -variationSum, minVarForThisPixel, maxVarForThisPixel, false); positionsUntested--; } } lastX = currentPoint.X; lastY = currentPoint.Y; mROI.GetNextPointOnXAxis(mSourceImage, ref currentPoint); } } // end unsafe block } catch (Exception e) { TestExecution().LogMessageWithTimeFromTrigger("ERROR: Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace); } finally { mFirstAxisScores = null; sourceBitmap.UnlockBits(sourceBitmapData); patternMinDownValues.UnlockBits(patternMinDownValuesBitmapData); patternMaxDownValues.UnlockBits(patternMaxDownValuesBitmapData); patternMinUpValues.UnlockBits(patternMinUpValuesBitmapData); patternMaxUpValues.UnlockBits(patternMaxUpValuesBitmapData); patternMinRightValues.UnlockBits(patternMinRightValuesBitmapData); patternMaxRightValues.UnlockBits(patternMaxRightValuesBitmapData); patternMinLeftValues.UnlockBits(patternMinLeftValuesBitmapData); patternMaxLeftValues.UnlockBits(patternMaxLeftValuesBitmapData); if (markedBitmap != null) { markedBitmap.UnlockBits(markedBitmapData); } } } if (mMarkedImage != null && mScoreFilter.Score > 0) { mScoreFilter.MarkImage(mMarkedImage.Bitmap, Color.Red); } mResult.SetValue(score); mResult.SetIsComplete(); if (mMarkedImage != null) { mMarkedImage.SetIsComplete(); } string msg = "PatternMatch " + Name + " completed; score=" + score; TestExecution().LogMessageWithTimeFromTrigger(msg); TestExecution().LogSummaryMessage(msg); if (score >= mAutoSaveOnScore || mScoreFilter.Score >= mAutoSaveOnCellScore) { try { string filePath = ((PatternMatchOfGrayVariationDefinition)Definition()).AutoSavePath; mSourceImage.Save(filePath, Name, true); if (mMarkedImage != null) { mMarkedImage.Save(filePath, Name, "_marked_" + score + "_" + mScoreFilter.Score); } TestExecution().LogMessageWithTimeFromTrigger("Snapshot saved"); } catch (ArgumentException e) { Project().Window().logMessage("ERROR: " + e.Message); TestExecution().LogErrorWithTimeFromTrigger(e.Message); } catch (Exception e) { Project().Window().logMessage("ERROR: Unable to AutoSave snapshot from " + Name + ". Ensure path valid and disk not full. Low-level message=" + e.Message); TestExecution().LogErrorWithTimeFromTrigger("Unable to AutoSave snapshot from " + Name + ". Ensure path valid and disk not full."); } } }