protected override void DoWork_impl()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            if (mEnabled && mSourceImage != null && mSourceImage.Bitmap != null)
            {
                mDuplicateImage.SetImage(new Bitmap(mSourceImage.Bitmap));
            }
            mDuplicateImage.SetIsComplete();

            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
        }
//		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");
        }
Exemplo n.º 3
0
//		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);
        }
Exemplo n.º 4
0
//		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 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.");
                }
            }
        }
Exemplo n.º 6
0
//		public const string AnalysisType = "Color Present Fails";
//		public override string Type() { return AnalysisType; }

        public override void DoWork()
        {
            //if (!mSourceImage.IsComplete() || !AreExplicitDependenciesComplete()) return;

            Bitmap sourceBitmap = SourceImage.Bitmap;
            Bitmap markedBitmap = null;

            TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " started");

            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();

                    int bottom = Math.Min(sourceBitmap.Height - 1, ROI.Bottom);
                    int top    = Math.Max(0, ROI.Top);
                    int left   = Math.Max(0, ROI.Left);
                    int right  = Math.Min(sourceBitmap.Width - 1, ROI.Right);
                    if (mTestXAxis)
                    {
                        TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " testing X Axis");
                        unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623
                        {
                            byte *sourcePointer;
                            byte *markedPointer;

                            for (int j = top; j <= bottom; j++)
                            {
                                sourcePointer  = (byte *)sourceBitmapData.Scan0;                                                              // init to first byte of image
                                sourcePointer += (j * stride) + (left * pixelByteWidth);                                                      // adjust to first byte of ROI row

                                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);
                                sourcePointer  += pixelByteWidth;                                                                             // adjust to next pixel to the right
                                for (int i = left + 1; i <= right; i++)                                                                       // starting at left+1 since we already have the value for "left"
                                {
                                    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);
                                    variation       = Math.Abs(pixel2Intensity - pixel1Intensity);
                                    if (variation > threshhold)
                                    {
                                        resultValue += variation;
                                        if (mMarkedImage != null)
                                        {
                                            markedPointer    = (byte *)markedBitmapData.Scan0;
                                            markedPointer   += (j * stride) + (i * pixelByteWidth);
                                            markedPointer[3] = Color.Yellow.A;
                                            markedPointer[2] = Color.Yellow.R;
                                            markedPointer[1] = Color.Yellow.G;
                                            markedPointer[0] = Color.Yellow.B;
                                        }
                                    }
                                    pixel1Intensity = pixel2Intensity;
                                    sourcePointer  += pixelByteWidth; // adjust to next pixel to the right
                                }
                                //sourcePointer += ((width-right)*pixelByteWidth) + strideOffset + (left * pixelByteWidth); // adjust to the first pixel of the next row by skipping the "extra bytes" (stride offset)
                            }
                        } // end unsafe block
                    }
                    if (mTestYAxis)
                    {
                        TestExecution().LogMessageWithTimeFromTrigger("IntensityVariation " + Name + " testing X Axis");
                        unsafe
                        {
                            byte *sourcePointer;
                            byte *markedPointer;

                            for (int i = left; i <= right; i++)
                            {
                                sourcePointer  = (byte *)sourceBitmapData.Scan0;        // init to first byte of image
                                sourcePointer += (top * stride) + (i * pixelByteWidth); // adjust to top pixel of the column

                                // get value for pixel on top of column...to init our for loop below (loop references two values)
                                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);
                                sourcePointer  += stride;                                                                                     // adjust to next pixel down the column

                                for (int j = top + 1; j <= bottom; j++)                                                                       // starting at top+1 since we already have the value for "top"
                                {
                                    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);
                                    variation       = Math.Abs(pixel2Intensity - pixel1Intensity);
                                    if (variation > threshhold)
                                    {
                                        resultValue += variation;
                                        if (mMarkedImage != null)
                                        {
                                            markedPointer    = (byte *)markedBitmapData.Scan0;
                                            markedPointer   += (j * stride) + (i * pixelByteWidth);
                                            markedPointer[3] = Color.Yellow.A;
                                            markedPointer[2] = Color.Yellow.R;
                                            markedPointer[1] = Color.Yellow.G;
                                            markedPointer[0] = Color.Yellow.B;
                                        }
                                    }
                                    pixel1Intensity = pixel2Intensity;
                                    sourcePointer  += stride; // move down one pixel on the y-axis
                                }
                            }
                        } // 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");
        }