Esempio n. 1
0
        private void DoThreshold()
        {
            switch (tabControl1.SelectedIndex)
            {
            case 0:
                // Local threshold
                LocalThresholdOptions options = new LocalThresholdOptions();
                options.DeviationWeight = (double)niblackUpDown.Value;
                if (localMethodBox.SelectedIndex == 0)
                {
                    options.Method = LocalThresholdMethod.NiBlack;
                }
                else
                {
                    options.Method = LocalThresholdMethod.BackgroundCorrection;
                }
                if (localObjectBox.SelectedIndex == 0)
                {
                    options.ParticleType = ParticleType.Bright;
                }
                else
                {
                    options.ParticleType = ParticleType.Dark;
                }
                options.WindowWidth  = (uint)localXSize.Value;
                options.WindowHeight = (uint)localYSize.Value;
                Algorithms.LocalThreshold(imageViewerOriginal.Image, imageViewerThresholded.Image, options);
                break;

            case 1:
                // Auto threshold
                // If we are looking for dark objects and the auto method is metric,
                // moment, or interclass variance we need to take the inverse of the image
                // first because AutoThreshold() looks for the bright objects for
                // these methods.
                Collection <ThresholdData> thresholdData;
                if (autoObjectBox.SelectedIndex == 1 && autoObjectBox.SelectedIndex > 1)
                {
                    // Use the thresholded image to temporarily hold the inverse image.  It
                    // will get set back to the threshold image after AutoThreshold() is called.
                    Algorithms.Inverse(imageViewerOriginal.Image, imageViewerThresholded.Image);
                    thresholdData = Algorithms.AutoThreshold(imageViewerThresholded.Image, imageViewerThresholded.Image, 2, (ThresholdMethod)autoMethodBox.SelectedIndex);
                }
                else
                {
                    thresholdData = Algorithms.AutoThreshold(imageViewerOriginal.Image, imageViewerThresholded.Image, 2, (ThresholdMethod)autoMethodBox.SelectedIndex);
                }
                Range thresholdRange;
                if (autoObjectBox.SelectedIndex == 1)
                {
                    // Look for dark objects
                    thresholdRange = new Range(0, thresholdData[0].Range.Maximum);
                }
                else
                {
                    // Look for bright objects
                    thresholdRange = new Range(thresholdData[0].Range.Minimum, 255);
                }
                Algorithms.Threshold(imageViewerOriginal.Image, imageViewerThresholded.Image, thresholdRange);
                break;

            case 2:
                // Manual threshold
                Algorithms.Threshold(imageViewerOriginal.Image, imageViewerThresholded.Image, new Range(manualMinimumSlide.Value, manualMaximumSlide.Value));
                break;
            }
        }
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Function Name: IVA_Classification_Segmentation
        //
        // Description  : Segments the classification image
        //
        // Parameters   : image                 - Input Image
        //                imageMask             - Segmented image
        //                roi                   - Region of Interest
        //                preprocessingOptions  - Preprocessing options
        //
        // Return Value : None
        //
        ////////////////////////////////////////////////////////////////////////////////
        public static void IVA_Classification_Segmentation(VisionImage image, VisionImage imageMask, Roi roi, ParticleClassifierPreprocessingOptions preprocessingOptions)
        {
            int useExpandedROI = 0;
            RectangleContour boundingBox = roi.GetBoundingRectangle(), expandedBox = roi.GetBoundingRectangle(), reducedBox = roi.GetBoundingRectangle();

            // Local Threshold method uses a kernel size, and the ROI must be larger than the kernel size for the function to work
            // Take care of making the ROI to extract larger if needed for the local threshold case
            if (preprocessingOptions.ThresholdType == ThresholdType.Local)
            {
                // Get the image size
                int xRes, yRes;
                xRes        = image.Width;
                yRes        = image.Height;
                boundingBox = roi.GetBoundingRectangle();

                // Take into account clipping of ROI. Just get ROI that's within bounds of image.
                if (Math.Min(xRes, (boundingBox.Left + boundingBox.Width)) - Math.Max(0, boundingBox.Left) < preprocessingOptions.LocalThresholdOptions.WindowWidth || Math.Min(yRes, (boundingBox.Top + boundingBox.Height)) - Math.Max(0, boundingBox.Top) < preprocessingOptions.LocalThresholdOptions.WindowHeight)
                {
                    // The ROI is smaller than the kernel. Try to expand the kernel in the directions needed to meet the minimum size required by the kernel.


                    int expandX     = (int)(preprocessingOptions.LocalThresholdOptions.WindowWidth / 2);
                    int expandY     = (int)(preprocessingOptions.LocalThresholdOptions.WindowHeight / 2);
                    int leftExpand  = expandX;
                    int rightExpand = expandX;
                    int leftSlack   = (int)boundingBox.Left;
                    int rightSlack  = (int)(xRes - (boundingBox.Left + boundingBox.Width));

                    if (leftExpand > leftSlack)
                    {
                        rightExpand += (leftExpand - leftSlack);
                    }

                    if (rightExpand > rightSlack)
                    {
                        leftExpand += (rightExpand - rightSlack);
                    }

                    int leftOut = (int)boundingBox.Left - leftExpand;
                    if (leftOut < 0)
                    {
                        leftOut = 0;
                    }
                    int rightOut = (int)(boundingBox.Left + boundingBox.Width + rightExpand);
                    if (rightOut > xRes)
                    {
                        rightOut = xRes;
                    }

                    int topExpand    = expandY;
                    int bottomExpand = expandY;
                    int topSlack     = (int)boundingBox.Top;
                    int bottomSlack  = (int)(yRes - (boundingBox.Top + boundingBox.Height));
                    if (topExpand > topSlack)
                    {
                        bottomExpand += (topExpand - topSlack);
                    }
                    if (bottomExpand > bottomSlack)
                    {
                        topExpand += (bottomExpand - bottomSlack);
                    }
                    int topOut = (int)(boundingBox.Top - topExpand);
                    if (topOut < 0)
                    {
                        topOut = 0;
                    }
                    int bottomOut = (int)(boundingBox.Top + boundingBox.Height + bottomExpand);
                    if (bottomOut > yRes)
                    {
                        bottomOut = yRes;
                    }
                    expandedBox.Initialize(leftOut, topOut, rightOut - leftOut, bottomOut - topOut);

                    // Create the reduced Rect so after performing the local threshold, we can reduce the size back to the original ROI dimensions.
                    reducedBox.Initialize(Math.Max(boundingBox.Left - leftOut, 0), Math.Max(boundingBox.Top - topOut, 0), boundingBox.Width + Math.Min(boundingBox.Left, 0), boundingBox.Height + Math.Min(boundingBox.Top, 0));

                    // Set this flag so the image can be reduced after performing the local threshold.
                    useExpandedROI = 1;
                }
            }

            // if Expanded Box hasn't been updated, use the boundingBox passed in to extract.
            if (useExpandedROI == 0)
            {
                expandedBox = boundingBox;
            }


            // Extract the region of interest into the mask image.
            Algorithms.Extract(image, imageMask, expandedBox, 1, 1);

            // Create a temporary ROI that will be used to mask the extracted image, to get rid of
            // the pixels outside of the rotated rectangle.
            Roi tmpROI = new Roi(roi);

            // If the ROI is a rotated rectangle, then compute the new location of the search ROI.
            if ((roi[0].Type == ContourType.RotatedRectangle) && (((RotatedRectangleContour)roi[0].Shape).Angle > 0.01))
            {
                CoordinateSystem baseSystem = new CoordinateSystem();
                baseSystem.Origin.X        = (roi.GetBoundingRectangle().Left < 0 ? 0 : roi.GetBoundingRectangle().Left);
                baseSystem.Origin.Y        = (roi.GetBoundingRectangle().Top < 0 ? 0 : roi.GetBoundingRectangle().Top);
                baseSystem.Angle           = 0;
                baseSystem.AxisOrientation = AxisOrientation.Direct;

                CoordinateSystem newSystem = new CoordinateSystem(new PointContour(0, 0), 0, AxisOrientation.Direct);

                CoordinateTransform transform = new CoordinateTransform(baseSystem, newSystem);

                Algorithms.TransformRoi(tmpROI, transform);
            }

            // Create a temporary image.
            using (VisionImage tmpImageMask = new VisionImage(ImageType.U8, 7))
            {
                double thresholdMin;
                double thresholdMax;

                switch (preprocessingOptions.ThresholdType)
                {
                case ThresholdType.Manual:
                    thresholdMin = preprocessingOptions.ManualThresholdRange.Minimum;
                    thresholdMax = preprocessingOptions.ManualThresholdRange.Maximum;
                    Algorithms.Threshold(imageMask, imageMask, new Range(thresholdMin, thresholdMax), true, 1);
                    break;

                case ThresholdType.Auto:
                    Collection <ThresholdData> thresholdData;
                    thresholdData = Algorithms.AutoThreshold(image, tmpImageMask, 2, preprocessingOptions.AutoThresholdOptions.Method);

                    if (preprocessingOptions.AutoThresholdOptions.ParticleType == ParticleType.Bright)
                    {
                        thresholdMin = (thresholdData[0].Range.Maximum > preprocessingOptions.AutoThresholdOptions.Limits.Minimum ?
                                        thresholdData[0].Range.Maximum : preprocessingOptions.AutoThresholdOptions.Limits.Minimum);
                        thresholdMax = 255;
                    }
                    else
                    {
                        thresholdMin = 0;
                        thresholdMax = (thresholdData[0].Range.Maximum < preprocessingOptions.AutoThresholdOptions.Limits.Maximum ?
                                        thresholdData[0].Range.Maximum : preprocessingOptions.AutoThresholdOptions.Limits.Maximum);
                    }
                    Algorithms.Threshold(imageMask, imageMask, new Range(thresholdMin, thresholdMax), true, 1);
                    break;

                case ThresholdType.Local:
                    LocalThresholdOptions Options = new LocalThresholdOptions(preprocessingOptions.LocalThresholdOptions.ParticleType, preprocessingOptions.LocalThresholdOptions.Method, 1.0, preprocessingOptions.LocalThresholdOptions.WindowWidth, preprocessingOptions.LocalThresholdOptions.WindowHeight);
                    Options.DeviationWeight = preprocessingOptions.LocalThresholdOptions.DeviationWeight;
                    Algorithms.LocalThreshold(imageMask, imageMask, Options);
                    break;

                default:
                    break;
                }

                /// If the expanded ROI was used, reduce it so no particles are found outside requested ROI.
                if (useExpandedROI == 1)
                {
                    Algorithms.Extract(imageMask, imageMask, reducedBox, 1, 1);
                }

                // Cast the image to 8 bit.
                imageMask.Type = ImageType.U8;

                // Eliminates particles that touch the border of the image.
                if (preprocessingOptions.RejectBorder)
                {
                    if ((roi[0].Type == ContourType.RotatedRectangle) && (((RotatedRectangleContour)roi[0].Shape).Angle > 0.01))
                    {
                        // Special case for the rotated rectangle.
                        Algorithms.Label(imageMask, imageMask, Connectivity.Connectivity8);

                        Collection <short> lookupTable = new Collection <short>();
                        lookupTable.Add(0);
                        for (int i = 1; i < 256; i++)
                        {
                            lookupTable.Add(1);
                        }

                        RoiProfileReport roiProfile = Algorithms.RoiProfile(imageMask, tmpROI);

                        for (int i = 0; i < roiProfile.Report.ProfileData.Count; i++)
                        {
                            lookupTable[0] = (short)roiProfile.Report.ProfileData[i];
                        }

                        Algorithms.UserLookup(imageMask, imageMask, lookupTable);
                    }
                    else
                    {
                        Algorithms.RejectBorder(imageMask, imageMask, Connectivity.Connectivity8);
                    }
                }

                // Remove small particles.
                if (preprocessingOptions.NumberOfErosions > 0)
                {
                    Algorithms.RemoveParticle(imageMask, imageMask, preprocessingOptions.NumberOfErosions, SizeToKeep.KeepLarge);
                }

                // If the rectangle is rotated, mask out the areas of the image that are not in the ROI.
                if ((roi[0].Type == ContourType.RotatedRectangle) && (((RotatedRectangleContour)roi[0].Shape).Angle > 0.01))
                {
                    // Perform the mask
                    Algorithms.RoiToMask(tmpImageMask, tmpROI, new PixelValue(255));
                    Algorithms.And(imageMask, tmpImageMask, imageMask);
                }

                // Sets the mask offset.
                imageMask.MaskOffset.X = Math.Max(0, roi.GetBoundingRectangle().Left);
                imageMask.MaskOffset.Y = Math.Max(0, roi.GetBoundingRectangle().Top);
            }
            tmpROI.Dispose();
        }
        public PaletteType ProcessImage(VisionImage image)
        {
            //vaParticleReportCalibrated = new ParticleMeasurementsReport();
            // Initialize the IVA_Data structure to pass results and coordinate systems.
            IVA_Data ivaData = new IVA_Data(15, 0);

            // Image Buffer: Push
            Functions.IVA_PushBuffer(ivaData, image, 0);

            // Operators: NOR Image
            Algorithms.Nor(image, Functions.IVA_GetBuffer(ivaData, 0), image);

            // Extract Color Plane
            using (VisionImage plane = new VisionImage(ImageType.U8, 7))
            {
                // Extract the red color plane and copy it to the main image.
                Algorithms.ExtractColorPlanes(image, ColorMode.Rgb, plane, null, null);
                Algorithms.Copy(plane, image);
            }

            // Thresholds an image into 2 classes by using local thresholding.
            LocalThresholdOptions vaLocalThresholdOptions = new LocalThresholdOptions();

            vaLocalThresholdOptions.DeviationWeight = 1;
            vaLocalThresholdOptions.Method          = LocalThresholdMethod.BackgroundCorrection;
            vaLocalThresholdOptions.ParticleType    = ParticleType.Dark;
            vaLocalThresholdOptions.ReplaceValue    = 1;
            vaLocalThresholdOptions.WindowHeight    = 35;
            vaLocalThresholdOptions.WindowWidth     = 35;
            Algorithms.LocalThreshold(image, image, vaLocalThresholdOptions);

            // Basic Morphology - Applies morphological transformations to binary images.
            int[] vaCoefficients            = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
            StructuringElement vaStructElem = new StructuringElement(3, 3, vaCoefficients);

            vaStructElem.Shape = StructuringElementShape.Square;
            // Applies morphological transformations
            Algorithms.Morphology(image, image, MorphologyMethod.GradientOut, vaStructElem);

            // Advanced Morphology: Fill Holes
            Algorithms.FillHoles(image, image, Connectivity.Connectivity8);

            // Advanced Morphology: Remove Objects
            int[] vaCoefficients2            = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
            StructuringElement vaStructElem2 = new StructuringElement(3, 3, vaCoefficients2);

            vaStructElem.Shape = StructuringElementShape.Hexagon;
            // Filters particles based on their size.
            Algorithms.RemoveParticle(image, image, 6, SizeToKeep.KeepLarge, Connectivity.Connectivity8, vaStructElem2);

            // Advanced Morphology: Remove Border Objects - Eliminates particles touching the border of the image.
            Algorithms.RejectBorder(image, image, Connectivity.Connectivity8);

            // Lookup Table: Equalize
            // Calculates the histogram of the image and redistributes pixel values
            // accross the desired range to maintain the same pixel value distribution.
            Range equalizeRange = new Range(0, 255);

            if (image.Type != ImageType.U8)
            {
                equalizeRange.Maximum = 0;
            }
            Algorithms.Equalize(image, image, null, equalizeRange, null);

            // Image Buffer: Push
            Functions.IVA_PushBuffer(ivaData, image, 1);

            // Particle Analysis - Computes the number of particles detected in a binary image and
            // returns the requested measurements about the particles.
            Collection <MeasurementType> vaPixelMeasurements      = new Collection <MeasurementType>(new MeasurementType[] { MeasurementType.BoundingRectLeft, MeasurementType.BoundingRectTop, MeasurementType.BoundingRectRight, MeasurementType.BoundingRectBottom, MeasurementType.MaxFeretDiameter });
            Collection <MeasurementType> vaCalibratedMeasurements = new Collection <MeasurementType>(new MeasurementType[] {});

            //IVA_Particle(image, Connectivity.Connectivity4, null, null, null, 10, out vaParticleReport, out vaParticleReportCalibrated);
            IVA_Particle(image, Connectivity.Connectivity4, vaPixelMeasurements, vaCalibratedMeasurements, ivaData, 10, out vaParticleReport, out vaParticleReportCalibrated);

            // Image Buffer: Pop
            Algorithms.Copy(Functions.IVA_GetBuffer(ivaData, 1), image);

            // Creates a new, empty region of interest.
            Roi roi = new Roi();
            // Creates a new RectangleContour using the given values.
            RectangleContour vaRect = new RectangleContour(0, 0, image.Width, image.Height);

            roi.Add(vaRect);
            // Classifies all the objects located in the given ROI.
            string vaClassifierFilePath = "C:\\DATA\\#hasilscan3\\Particle Classifier.clf";

            vaClassifierReports = IVA_Classify(image, roi, vaClassifierFilePath);
            VisGrainTypeCollection colType = new VisGrainTypeCollection(vaClassifierReports);

            roi.Dispose();

            // Image Buffer: Pop
            Algorithms.Copy(Functions.IVA_GetBuffer(ivaData, 1), image);

            // Creates a new, empty region of interest.
            Roi roi2 = new Roi();
            // Creates a new RectangleContour using the given values.
            RectangleContour vaRect2 = new RectangleContour(0, 0, image.Width, image.Height);

            roi2.Add(vaRect2);
            // Classifies all the objects located in the given ROI.
            string vaClassifierFilePath2 = "C:\\DATA\\#hasilscan3\\Ukuran Classifier.clf";

            vaClassifierReports2 = IVA_Classify(image, roi2, vaClassifierFilePath2);
            VisGrainSizeCollection colSize = new VisGrainSizeCollection(vaClassifierReports2);

            GrainResults = new VisGrainDataCollection(vaClassifierReports, vaClassifierReports2, ListShape);

            roi2.Dispose();

            // Dispose the IVA_Data structure.
            ivaData.Dispose();

            // Return the palette type of the final image.
            return(PaletteType.Binary);
        }