/// <summary> /// Convert image of double type to byte type using a clamp /// </summary> private static byte[,] Double2DtoByte2D(double[,] image) { var result = new byte[image.GetLength(0), image.GetLength(1)]; for (var x = 0; x < image.GetLength(0); x++) { for (var y = 0; y < image.GetLength(1); y++) { result[x, y] = (byte)EdgeDetection.ImageClamp2(Math.Round(image[x, y])); } } return(result); }
/// <summary> /// Perform Canny edge detection /// </summary> public static byte[,] CannyEdgeDetector(byte[,] input, int blur = 1, byte high = 90, byte low = 90) { var copy = BilateralFilter.BilateralFilter2D(input); // Preprocessing before detecting edges // ======================= Adapted Sobel edge detection from earlier implementation ======================= var image1 = Convolution.Convolve(copy, EdgeDetection.SobelKernel3X3V, 1); var image2 = Convolution.Convolve(copy, EdgeDetection.SobelKernel3X3H, 1); var midImage1 = new double[image1.GetLength(0), image1.GetLength(1)]; for (var x = 0; x < midImage1.GetLength(0); x++) { for (var y = 0; y < midImage1.GetLength(1); y++) { var final = Math.Sqrt(image1[x, y] * image1[x, y] + image2[x, y] * image2[x, y]); midImage1[x, y] = (byte)EdgeDetection.ImageClamp2(Math.Round(final)); } } var image3 = Convolution.Convolve(copy, EdgeDetection.SobelKernel3X3Minv, 1); var image4 = Convolution.Convolve(copy, EdgeDetection.SobelKernel3X3Minh, 1); var midImage2 = new double[image1.GetLength(0), image1.GetLength(1)]; for (var x = 0; x < midImage2.GetLength(0); x++) { for (var y = 0; y < midImage2.GetLength(1); y++) { var final = Math.Sqrt(image3[x, y] * image3[x, y] + image4[x, y] * image4[x, y]); midImage2[x, y] = (byte)EdgeDetection.ImageClamp2(Math.Round(final)); } } var imageG = new double[image1.GetLength(0), image1.GetLength(1)]; for (var x = 0; x < midImage2.GetLength(0); x++) { for (var y = 0; y < midImage2.GetLength(1); y++) { var final = midImage1[x, y] + midImage2[x, y];/*Math.Sqrt(midImage1[x, y] * midImage1[x, y] + midImage2[x, y] * midImage2[x, y]);*/ imageG[x, y] = (byte)EdgeDetection.ImageClamp2(Math.Round(final)); } } var imageT = new int[midImage1.GetLength(0), midImage1.GetLength(1)]; for (var x = 0; x < imageT.GetLength(0); x++) { for (var y = 0; y < imageT.GetLength(1); y++) { imageT[x, y] = (int)Math.Round(Math.Atan2(midImage2[x, y], midImage2[x, y]) * (5.0 / Math.PI) + 5) % 5; } } // ======================================================================================================== var suppressed = Suppress(imageG, imageT); //Perform Non-maximum suppression var highEdges = HelperFunctions.ThresholdDouble(suppressed, high); // Keep the strong edges in one map var lowEdges = HelperFunctions.ThresholdDouble(suppressed, low); // Keep weaker edges in another map var highEdgesByte = Double2DtoByte2D(highEdges); var lowEdgesByte = Double2DtoByte2D(lowEdges); var CombinedThresholds = BinaryOperators.ORoperator(highEdgesByte, lowEdgesByte); // Hysteresis to trace edges return(Hysteresis(highEdgesByte, CombinedThresholds)); }
private void applyButton_Click(object sender, EventArgs e) { if (this._inputImage == null) { return; } this._outputImage?.Dispose(); this._outputImage = new Bitmap(this._inputImage.Size.Width, this._inputImage.Size.Height); var image = new Color[this._inputImage.Size.Width, this._inputImage.Size.Height]; var image2 = new Color[this._inputImage2.Size.Width, this._inputImage2.Size.Height]; // Setup progress bar this.progressBar.Visible = true; this.progressBar.Minimum = 1; this.progressBar.Maximum = this._inputImage.Size.Width * this._inputImage.Size.Height; this.progressBar.Value = 1; this.progressBar.Step = 1; // Copy input Bitmap to array for (var x = 0; x < this._inputImage.Size.Width; x++) { for (var y = 0; y < this._inputImage.Size.Height; y++) { image[x, y] = this._inputImage.GetPixel(x, y); // Set pixel color in array at (x,y) } } // Copy input Bitmap to array for the control image for (var x = 0; x < this._inputImage2.Size.Width; x++) { for (var y = 0; y < this._inputImage2.Size.Height; y++) { image2[x, y] = this._inputImage2.GetPixel(x, y); // Set pixel color in array at (x,y) } } //================================================================================== //================================= PIPELINE ======================================= //================================================================================== //RESET VARS FROM PREVIOUS IMAGE: FloodFill.ObjectCount = 0; FloodFill.Objects = new List <PictureObject>(); //===================== Preprocessing: Filtering, Segmentation ===================== var greyscale = HelperFunctions.Greyscalize(image); HelperFunctions.GlobalMask = HelperFunctions.Greyscalize(image2); //===================== Edge Detection ============================================= var detectSides = CannyEdge.CannyEdgeDetector(greyscale, 1, GlobalThreshold.OtsuThreshold(greyscale)); //===================== Find sides of road poles using Hough transform ============= var lines = HoughTransform.FoundLines(detectSides, 0, 0); var cartLines = HoughExtensions.GetAllCartesianLines(lines, detectSides); var pairs = HoughExtensions.GetPairs(cartLines, detectSides.GetLength(1)); var roughPairs = HoughExtensions.GetRoughPairs(cartLines, detectSides.GetLength(1)); //===================== Find lower and upper boundaries of poles =================== var workingImage = BilateralFilter.BilateralFilter2D(greyscale); workingImage = EdgeDetection.DetectEdges(HelperFunctions.Threshold(workingImage, GlobalThreshold.OtsuThreshold(workingImage))); detectSides = HoughExtensions.CleanOutsidePairs(workingImage, roughPairs); detectSides = FloodFill.MarkObjects(detectSides); detectSides = FloodFill.filterObjects(detectSides); //================================================================================== //================================================================================== //================================================================================== var nDV = ValueCounter(detectSides); this.label2.Text = "Number of distinct values: " + nDV; Console.ForegroundColor = ConsoleColor.Magenta; Console.WriteLine("[Done] Final image with size " + detectSides.GetLength(0) + "x" + detectSides.GetLength(1) + " and " + nDV + " distinct Values"); Console.ResetColor(); var newImage = Colorize(detectSides); DrawBoundingBox(newImage); var outputResized = new Bitmap(this._outputImage, detectSides.GetLength(0), detectSides.GetLength(1)); // Copy array to output Bitmap for (var x = 0; x < newImage.GetLength(0); x++) { for (var y = 0; y < newImage.GetLength(1); y++) { outputResized.SetPixel(x, y, newImage[x, y]); // Set the pixel color at coordinate (x,y) } } var g = Graphics.FromImage(outputResized); DrawPairs(pairs, outputResized); // Draw pairs generated by hough transform FloodFill.DrawFinal(this._inputImage, pairs); pictureBox2.Image = this._inputImage; // Display output image - replace InputImage with OutputResized to see hough pairs and object map with bounding boxes progressBar.Visible = true; // Hide progress bar }