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