private static double[][] ToInitialDistanceMap(PNM image, ref int pixelCount) { double[][] distanceMap = new double[image.Width][]; for(int i =0; i< image.Width; i++) { distanceMap[i] = new double[image.Height]; } byte l; for (int i = 0; i < image.Width; i++) { for (int j = 0; j < image.Height; j++) { image.GetPixel(i, j, out l, out l, out l); if (l == 255) { distanceMap[i][j] = 0; pixelCount++; } else { distanceMap[i][j] = Double.PositiveInfinity; } } } return distanceMap; }
public static Func<byte, byte, byte, Pixel> Equalize(PNM pnm) { double[] rawDataR = pnm.GetHistogramRed(); double[] rawDataG = pnm.GetHistogramGreen(); double[] rawDataB = pnm.GetHistogramBlue(); double[] rlum = new double[256]; double[] glum = new double[256]; double[] blum = new double[256]; double cumulatedR = 0; double cumulatedG = 0; double cumulatedB = 0; for (int i = 0; i < 256; i++) { cumulatedR += rawDataR[i]; cumulatedG += rawDataG[i]; cumulatedB += rawDataB[i]; rlum[i] = cumulatedR; glum[i] = cumulatedG; blum[i] = cumulatedB; } return (r, g, b) => { return new Pixel(Convert.ToByte(rlum[r] * 255), Convert.ToByte(glum[g] * 255), Convert.ToByte(blum[b] * 255)); }; }
public static Func <byte, byte, byte, Pixel> Equalize(PNM pnm) { double[] rawDataR = pnm.GetHistogramRed(); double[] rawDataG = pnm.GetHistogramGreen(); double[] rawDataB = pnm.GetHistogramBlue(); double[] rlum = new double[256]; double[] glum = new double[256]; double[] blum = new double[256]; double cumulatedR = 0; double cumulatedG = 0; double cumulatedB = 0; for (int i = 0; i < 256; i++) { cumulatedR += rawDataR[i]; cumulatedG += rawDataG[i]; cumulatedB += rawDataB[i]; rlum[i] = cumulatedR; glum[i] = cumulatedG; blum[i] = cumulatedB; } return((r, g, b) => { return new Pixel(Convert.ToByte(rlum[r] * 255), Convert.ToByte(glum[g] * 255), Convert.ToByte(blum[b] * 255)); }); }
private static PNM DrawLines(PNM image, IEnumerable <Tuple <Point, Point> > lines) { // prepare the bitmap using (Bitmap bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb)) { BitmapData data = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] stridedBuffer = Stride(image.raster, image.Width, image.Height); Marshal.Copy(stridedBuffer, 0, data.Scan0, stridedBuffer.Length); bitmap.UnlockBits(data); using (Graphics graphics = Graphics.FromImage(bitmap)) { // draw the lines foreach (var tuple in lines) { graphics.DrawLine(Pens.Blue, tuple.Item1, tuple.Item2); } } // get raw data PNM lineImage = new PNM(image.Width, image.Height); data = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); lineImage.raster = UnStride(data.Scan0, image.Width, image.Height); bitmap.UnlockBits(data); return(lineImage); } }
internal static int[][] HoughVote(PNM image, int maxW) { // initialize voting board int[][] votingBoard = new int[180][]; for (int i = 0; i < 180; i++) { votingBoard[i] = new int[maxW * 2]; } int size = image.Width * image.Height; for (int i = 0; i < size; i++) { byte l; image.GetPixel(i, out l, out l, out l); if (l < 255) { continue; } double centeredX = i % image.Width - (image.Width / 2d); double centeredY = (image.Height / 2d) - i / image.Width; // pixel is white - vote in all directions for (int angle = 0; angle < 180; angle++) { double radianAngle = Math.PI * angle / 180d; double w = centeredX * Math.Cos(radianAngle) + centeredY * Math.Sin(radianAngle); votingBoard[angle][(int)w + maxW]++; } } return(votingBoard); }
// assume k = -0.2 and R = 15x15 // needs 1 pixel width padding public static Pixel Niblack(PNM image, int index, double k = -0.2, int length = 15, int padding = 7) { byte r, g, b; float[] surrounding = new float[length * length]; int i = 0; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out r, out g, out b); surrounding[i] = PNM.RGBToLuminosity(r, g, b); i++; } } float mean = surrounding.Average(); double threshold = mean + (k * (mean / surrounding.Length)); image.GetPixel(index, out r, out g, out b); byte luminosity = PNM.RGBToLuminosity(r, g, b); if (luminosity < threshold) { return(Pixel.Black); } return(Pixel.White); }
public static Func <byte, byte, byte, Pixel> Otsu(PNM image) { double[] histogram = image.GetHistogramLuminosity(); object compareLock = new object(); double[] variances = new double[256]; Parallel.For(0, 256, i => { double[] background = histogram.Take(i).ToArray(); double[] foreground = histogram.Skip(i).ToArray(); double backgroundWeight = background.Sum(); double foregroundWeight = 1 - backgroundWeight; double backgroundMean = background.Length == 0 ? 0 : background.Select((d, idx) => d * idx).Average(); double foregroundMean = foreground.Select((d, idx) => d * idx).Average(); double variance = backgroundWeight * foregroundWeight * Math.Pow(foregroundMean - backgroundMean, 2); variances[i] = variance; }); byte threshold = 0; double maxVariance = Double.NegativeInfinity; for (int i = 0; i < 256; i++) { if (variances[i] > maxVariance) { maxVariance = variances[i]; threshold = (byte)i; } } return((r, g, b) => Plain(r, g, b, threshold)); }
public static Func<byte, byte, byte, Pixel> Otsu(PNM image) { double[] histogram = image.GetHistogramLuminosity(); object compareLock = new object(); double[] variances = new double[256]; Parallel.For(0, 256, i => { double[] background = histogram.Take(i).ToArray(); double[] foreground = histogram.Skip(i).ToArray(); double backgroundWeight = background.Sum(); double foregroundWeight = 1 - backgroundWeight; double backgroundMean = background.Length == 0 ? 0 : background.Select((d, idx) => d * idx).Average(); double foregroundMean = foreground.Select((d, idx) => d * idx).Average(); double variance = backgroundWeight * foregroundWeight * Math.Pow(foregroundMean - backgroundMean, 2); variances[i] = variance; }); byte threshold = 0; double maxVariance = Double.NegativeInfinity; for(int i =0; i< 256;i++) { if (variances[i] > maxVariance) { maxVariance = variances[i]; threshold = (byte)i; } } return (r, g, b) => Plain(r, g, b, threshold); }
public static Pixel Erosion(PNM image, int index) { int length = 3; int padding = 1; byte r = 0, g = 0, b = 0; byte tempR, tempG, tempB; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out tempR, out tempG, out tempB); // check for "white pixel" if (tempR > 127) r = 255; if (tempG > 127) g = 255; if (tempB > 127) b = 255; } if (r != 0 && g != 0 && b != 0) break; } return new Pixel(r, g, b); }
// assume mask 3x3, image is already 1 pixel padded public static Pixel Median(PNM image, int index) { byte[] workArrayR = new byte[9]; byte[] workArrayG = new byte[9]; byte[] workArrayB = new byte[9]; int length = 3; int padding = 1; byte r, g, b; int i = 0; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out r, out g, out b); workArrayR[i] = r; workArrayG[i] = g; workArrayB[i] = b; i++; } } Array.Sort(workArrayR); Array.Sort(workArrayG); Array.Sort(workArrayB); return new Pixel(workArrayR[4], workArrayG[4], workArrayB[4]); }
private static PNM DrawLines(PNM image, IEnumerable<Tuple<Point, Point>> lines) { // prepare the bitmap using (Bitmap bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb)) { BitmapData data = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] stridedBuffer = Stride(image.raster, image.Width, image.Height); Marshal.Copy(stridedBuffer, 0, data.Scan0, stridedBuffer.Length); bitmap.UnlockBits(data); using (Graphics graphics = Graphics.FromImage(bitmap)) { // draw the lines foreach(var tuple in lines) { graphics.DrawLine(Pens.Blue, tuple.Item1, tuple.Item2); } } // get raw data PNM lineImage = new PNM(image.Width, image.Height); data = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); lineImage.raster = UnStride(data.Scan0, image.Width, image.Height); bitmap.UnlockBits(data); return lineImage; } }
internal static Pixel ConvoluteWithModule(PNM image, int index, float[] matrix1, float[] matrix2, int length, int padding) { float sumR1 = 0; float sumR2 = 0; float sumG1 = 0; float sumG2 = 0; float sumB1 = 0; float sumB2 = 0; byte r, g, b; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out r, out g, out b); float coeff1 = matrix1[(m * length) + n]; float coeff2 = matrix2[(m * length) + n]; sumR1 += r * coeff1; sumR2 += r * coeff2; sumG1 += g * coeff1; sumG2 += g * coeff2; sumB1 += b * coeff1; sumB2 += b * coeff2; } } return(new Pixel(Filter.Coerce(Module(sumR1, sumR2)), Filter.Coerce(Module(sumG1, sumG2)), Filter.Coerce(Module(sumB1, sumB2)))); }
public static Pixel Dilation(PNM image, int index) { int length = 3; int padding = 1; byte r = 255, g = 255, b = 255; byte tempR, tempG, tempB; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out tempR, out tempG, out tempB); // check for "black pixel" if (tempR < 128) r = 0; if (tempG < 128) g = 0; if (tempB < 128) b = 0; } if (r == 0 && g == 0 && b == 0) break; } return new Pixel(r, g, b); }
private static void HysteresisConnect(PNM image, int index, int width, int height, byte lowValue, byte highValue) { int x = index % width; int y = index / height; for (int x0 = x - 1; x0 < x + 1; x0++) { for (int y0 = y - 1; y0 < y + 1; y0++) { int currentIndex = (width * y0) + x0; if (!IsPixelOnEdge(currentIndex, width, height)) { byte l; image.GetPixel(currentIndex, out l, out l, out l); if (l != 255) { if (l >= lowValue) { image.SetPixel(currentIndex, 255, 255, 255); HysteresisConnect(image, currentIndex, width, height, lowValue, highValue); } } } } } }
private static Pixel FishEye(PNM image, int index, double maxR) { byte r,g,b; double radius, angle; image.ToPolar(index, out radius, out angle); image.GetPixel((radius * radius) / maxR, angle, out r, out g, out b); return new Pixel(r, g, b); }
private static Pixel FishEye(PNM image, int index, double maxR) { byte r, g, b; double radius, angle; image.ToPolar(index, out radius, out angle); image.GetPixel((radius * radius) / maxR, angle, out r, out g, out b); return(new Pixel(r, g, b)); }
// pixel_intensity >= threshold == white object // pixel_intensity < threshold == black background public static Pixel Plain(byte r, byte g, byte b, byte threshold) { byte lum = PNM.RGBToLuminosity(r, g, b); if (lum >= threshold) { return(Pixel.White); } return(Pixel.Black); }
public static PNM ApplyHoughDetector(this PNM image) { // greyscale, edge detection, thresholding PNM workImage = PNM.Copy(image).ApplyPointProcessing(Color.ToGrayscale) .ApplyGradientEdgesDetection() .ApplyPointProcessing(Thresholding.Entropy(image)); IEnumerable <Tuple <Point, Point> > lines = GenerateHoughLines(workImage); return(DrawLines(image, lines)); }
private Bitmap ReadBitmap(string path) { if (path.EndsWith("pgm")) { return(PNM.ReadPNM(listdata[pathIndex].filePath) as Bitmap); } else { return(new Bitmap(listdata[pathIndex].filePath)); } }
public static Func <byte, byte, byte, Pixel> Triangle(PNM image) { double[] histogram = image.GetHistogramLuminosity(); int minx = 0, maxx = 0; double minValue = Double.PositiveInfinity, maxValue = Double.NegativeInfinity; // find min max for (int i = 0; i < 256; i++) { if (histogram[i] >= maxValue) { maxValue = histogram[i]; maxx = i; } if (histogram[i] < minValue) { minValue = histogram[i]; minx = i; } } // find line double a = -(maxValue - minValue) / (maxx - minx); double b = 1; double c = (minx * (maxValue - minValue) / (maxx - minx)) - minValue; // find the furthest point double distance, maxDistance = Double.NegativeInfinity; byte threshold = 0; int from, to; if (minx < maxx) { from = minx + 1; to = maxx; } else { to = minx + 1; from = maxx; } for (int i = from; i < to; i++) { distance = PointToLineDistance(a, b, c, i, histogram[i]); if (distance >= maxDistance) { maxDistance = distance; threshold = (byte)i; } } return((pr, pg, pb) => Plain(pr, pg, pb, threshold)); }
public static PNM ApplyDistanceTransform(this PNM image) { PNM binaryImage = image.ApplyCannyDetector(); int pixelCount = 0; double[][] distanceMap = ToInitialDistanceMap(binaryImage, ref pixelCount); CalculateDistances(distanceMap, pixelCount); PNM distancedImage = new PNM(image.Width, image.Height); for(int i=0; i < image.Width * image.Height; i++) { byte distance = Filter.Coerce(distanceMap[i % image.Width][i / image.Width]); distancedImage.SetPixel(i, distance, distance, distance); } return distancedImage; }
public static Func<byte, byte, byte, Pixel> Triangle(PNM image) { double[] histogram = image.GetHistogramLuminosity(); int minx=0, maxx=0; double minValue = Double.PositiveInfinity, maxValue = Double.NegativeInfinity; // find min max for (int i = 0; i < 256; i++) { if (histogram[i] >= maxValue) { maxValue = histogram[i]; maxx = i; } if (histogram[i] < minValue) { minValue = histogram[i]; minx = i; } } // find line double a = -(maxValue - minValue) / (maxx - minx); double b = 1; double c = (minx * (maxValue - minValue) / (maxx - minx)) - minValue; // find the furthest point double distance, maxDistance = Double.NegativeInfinity; byte threshold = 0; int from, to; if (minx < maxx) { from = minx + 1; to = maxx; } else { to = minx + 1; from = maxx; } for(int i = from; i< to; i++) { distance = PointToLineDistance(a,b,c,i,histogram[i]); if (distance >= maxDistance) { maxDistance = distance; threshold = (byte)i; } } return (pr, pg, pb) => Plain(pr, pg, pb, threshold); }
private static PNM ApplyHysteresis(byte[] suppressed, int width, int height, double low, double high) { PNM image = new PNM(width, height); byte lowValue = (byte)(low * 255); byte highValue = (byte)(high * 255); for (int i = 0; i < suppressed.Length; i++) { if (suppressed[i] >= highValue) { image.SetPixel(i, 255, 255, 255); HysteresisConnect(image, i, width, height, lowValue, highValue); } } return(image); }
public static PNM ApplyDistanceTransform(this PNM image) { PNM binaryImage = image.ApplyCannyDetector(); int pixelCount = 0; double[][] distanceMap = ToInitialDistanceMap(binaryImage, ref pixelCount); CalculateDistances(distanceMap, pixelCount); PNM distancedImage = new PNM(image.Width, image.Height); for (int i = 0; i < image.Width * image.Height; i++) { byte distance = Filter.Coerce(distanceMap[i % image.Width][i / image.Width]); distancedImage.SetPixel(i, distance, distance, distance); } return(distancedImage); }
// returns list tuples which encode interesection of lines with image edges private static IEnumerable<Tuple<Point, Point>> GenerateHoughLines(PNM image) { double maxR = Math.Sqrt(Math.Pow(image.Width / 2d, 2) + Math.Pow(image.Height / 2d, 2)); int maxW = (int)Math.Ceiling(maxR); int[][] votingBoard = HoughVote(image, maxW); // prepare function Func<double, double, Tuple<Point, Point>> polarLinesToEdges = (dist, ang) => PolarLineToImageEdges(dist, ang, image.Width, image.Height); // pick top 10 // MADNESS return votingBoard //.AsParallel() .SelectMany((array, angle) => array.Select((count, distance) => new { Angle = angle, Distance = distance, Count = count })) .Where(a => a.Count > maxW/2 ) .Select((a) => new { Distance = a.Distance - maxW, Angle = Math.PI * a.Angle / 180d }) .Select((a) => polarLinesToEdges(a.Distance, a.Angle)) .Where(tupl => tupl != null); }
public static PNM ApplyCannyDetector(this PNM image) { PNM workImage = image.ApplyPointProcessing(Color.ToGrayscale) .ApplyConvolutionMatrix(new float[] { 0, 0.01F, 0.02F, 0.01F, 0, 0.01F, 0.06F, 0.1F, 0.06F, 0.01F, 0.02F, 0.1F, 0.16F, 0.1F, 0.02F, 0.01F, 0.06F, 0.1F, 0.06F, 0.01F, 0, 0.01F, 0.02F, 0.01F, 0 }, 1, 0); Filter.Pad(workImage, 1); float[] xraster = Filter.ApplyConvolutionUnbound(workImage, SobelX, 3).Item1; float[] yraster = Filter.ApplyConvolutionUnbound(workImage, SobelY, 3).Item1; var vectorField = xraster.Zip(yraster, (x, y) => Tuple.Create(Module(x, y), GetOrientation(x, y))).ToArray(); byte[] suppressed = NonMaximumSuppression(vectorField, image.Width, image.Height); return(ApplyHysteresis(suppressed, image.Width, image.Height, 0.05, 0.2)); }
public static PNM ApplyZeroCrossingDetector(this PNM image) { // preprare PNM workImage = PNM.Copy(image); Filter.Pad(workImage, 4); // apply loG Tuple <float[], float[], float[]> LoGRaster = Filter.ApplyConvolutionUnbound(workImage, LoG, 9); PNM returnImage = new PNM(image.Width, image.Height); // Apply zero crossing except last row and last column Parallel.For(0, image.Height - 1, i => { for (int j = 0; j < image.Width - 1; j++) { byte r = 0; byte g = 0; byte b = 0; // current index position int position = i * image.Width + j; float currentR = LoGRaster.Item1[position]; float neighbourR = LoGRaster.Item1[position + image.Width + 1]; float currentG = LoGRaster.Item2[position]; float neighbourG = LoGRaster.Item2[position + image.Width + 1]; float currentB = LoGRaster.Item3[position]; float neighbourB = LoGRaster.Item3[position + image.Width + 1]; if ((currentR * neighbourR) < 0 && (Math.Abs(currentR) < Math.Abs(neighbourR))) { r = 255; } if ((currentG * neighbourG) < 0 && (Math.Abs(currentG) < Math.Abs(neighbourG))) { g = 255; } if ((currentB * neighbourB) < 0 && (Math.Abs(currentB) < Math.Abs(neighbourB))) { b = 255; } returnImage.SetPixel(position, r, g, b); } }); return(returnImage); }
// returns list tuples which encode interesection of lines with image edges private static IEnumerable <Tuple <Point, Point> > GenerateHoughLines(PNM image) { double maxR = Math.Sqrt(Math.Pow(image.Width / 2d, 2) + Math.Pow(image.Height / 2d, 2)); int maxW = (int)Math.Ceiling(maxR); int[][] votingBoard = HoughVote(image, maxW); // prepare function Func <double, double, Tuple <Point, Point> > polarLinesToEdges = (dist, ang) => PolarLineToImageEdges(dist, ang, image.Width, image.Height); // pick top 10 // MADNESS return(votingBoard //.AsParallel() .SelectMany((array, angle) => array.Select((count, distance) => new { Angle = angle, Distance = distance, Count = count })) .Where(a => a.Count > maxW / 2) .Select((a) => new { Distance = a.Distance - maxW, Angle = Math.PI * a.Angle / 180d }) .Select((a) => polarLinesToEdges(a.Distance, a.Angle)) .Where(tupl => tupl != null)); }
private void SetPathToWindow(TrainingData path) { FilePathValue.Text = path.filePath.Substring(path.filePath.LastIndexOf('\\') + 1); currentData.filePath = path.filePath; CBGender.SelectedValue = path.label; Bitmap source; if (currentData.filePath.EndsWith("pgm")) { Bitmap bmp = PNM.ReadPNM(currentData.filePath) as Bitmap; ColorImage imgDetec = new ColorImage(bmp); faces = _genderClassifier.GetFaces(imgDetec); foreach (Rectangle face in faces) { imgDetec.Draw(face, new Emgu.CV.Structure.Bgr(System.Drawing.Color.AliceBlue), 1); } TBFaces.Text = string.Format("Faces: {0}", faces.Count); source = imgDetec.ToBitmap(); } else { BitmapImage bi3 = new BitmapImage(); bi3.BeginInit(); bi3.UriSource = new Uri(currentData.filePath, UriKind.Absolute); bi3.EndInit(); ColorImage imgDetec = new ColorImage(bi3.ToBitmap()); faces = _genderClassifier.GetFaces(imgDetec); foreach (Rectangle face in faces) { imgDetec.Draw(face, new Emgu.CV.Structure.Bgr(System.Drawing.Color.AliceBlue), 1); } TBFaces.Text = string.Format("Faces: {0}", faces.Count); source = imgDetec.ToBitmap(); } TBDimen.Text = string.Format("W: {0} H: {1}", (int)source.Width, (int)source.Height); if (CBTrainer.IsChecked == true) { GrayImage img = new GrayImage(source); img.Processing(); source = img.ToBitmap(); } Photo.Source = source.ToBitmapImage(); }
public static Pixel Mirror(PNM image, int index) { byte r, g, b; int x = index % image.Width; int y = index / image.Width; if (x < image.Width / 2d) image.GetPixel((y * image.Width) + (image.Width - x - 1), out r, out g, out b); else image.GetPixel((y * image.Width) + x, out r, out g, out b); /* image.ToPolar(index, out radius, out angle); double newX = image.Width * angle/Math.PI*2; double newY = image.Height * radius / maxR; int newIndex = ((int)newX * image.Width) + (int)newY; // correct for pixels outside the image if(newIndex < 0 || newIndex >= image.Width * image.Height) newIndex = index; image.GetPixel(radius, angle + radius, out r, out g, out b); * */ return new Pixel(r, g, b); }
// Kapur's method public static Func <byte, byte, byte, Pixel> Entropy(PNM image) { double[] histogram = image.GetHistogramLuminosity(); double entropySum = Double.NegativeInfinity; int threshold = 0; for (int i = 0; i < 256; i++) { double[] background = histogram.Take(i + 1).ToArray(); double[] foreground = histogram.Skip(i + 1).ToArray(); double sumB = background.Sum(); double sumF = foreground.Sum(); double entropyB = -background.Select(p => { if (p == 0) { return(0); } return((p / sumB) * Math.Log(p / sumB, 2)); }) .Sum(); double entropyF = -foreground.Select(p => { if (p == 0) { return(0); } return((p / (1 - sumB)) * Math.Log(p / (1 - sumB), 2)); }) .Sum(); double sum = entropyB + entropyF; if (sum > entropySum) { entropySum = sum; threshold = i; } } return((r, g, b) => Plain(r, g, b, (byte)threshold)); }
public static Func <byte, byte, byte, Pixel> Stretch(PNM pnm) { double[] histogramR = pnm.GetHistogramRed(); double[] histogramG = pnm.GetHistogramGreen(); double[] histogramB = pnm.GetHistogramBlue(); double[] cumulativeR = CumulativeHistogram(histogramR); double[] cumulativeG = CumulativeHistogram(histogramG); double[] cumulativeB = CumulativeHistogram(histogramB); Tuple <int, int> rangeR = FindPercentiles(cumulativeR); Tuple <int, int> rangeG = FindPercentiles(cumulativeG); Tuple <int, int> rangeB = FindPercentiles(cumulativeB); int[] LUTR = GetStretchLUT(histogramR, rangeR.Item1, rangeR.Item2); int[] LUTG = GetStretchLUT(histogramG, rangeG.Item1, rangeG.Item2); int[] LUTB = GetStretchLUT(histogramB, rangeB.Item1, rangeB.Item2); return((r, g, b) => { return new Pixel(Convert.ToByte(LUTR[r]), Convert.ToByte(LUTG[g]), Convert.ToByte(LUTB[b])); }); }
public static Func<byte, byte, byte, Pixel> Stretch(PNM pnm) { double[] histogramR = pnm.GetHistogramRed(); double[] histogramG = pnm.GetHistogramGreen(); double[] histogramB = pnm.GetHistogramBlue(); double[] cumulativeR = CumulativeHistogram(histogramR); double[] cumulativeG = CumulativeHistogram(histogramG); double[] cumulativeB = CumulativeHistogram(histogramB); Tuple<int, int> rangeR = FindPercentiles(cumulativeR); Tuple<int, int> rangeG = FindPercentiles(cumulativeG); Tuple<int, int> rangeB = FindPercentiles(cumulativeB); int[] LUTR = GetStretchLUT(histogramR, rangeR.Item1, rangeR.Item2); int[] LUTG = GetStretchLUT(histogramG, rangeG.Item1, rangeG.Item2); int[] LUTB = GetStretchLUT(histogramB, rangeB.Item1, rangeB.Item2); return (r, g, b) => { return new Pixel(Convert.ToByte(LUTR[r]), Convert.ToByte(LUTG[g]), Convert.ToByte(LUTB[b])); }; }
public static PNM ApplyZeroCrossingDetector(this PNM image) { // preprare PNM workImage = PNM.Copy(image); Filter.Pad(workImage, 4); // apply loG Tuple<float[], float[], float[]> LoGRaster = Filter.ApplyConvolutionUnbound(workImage, LoG, 9); PNM returnImage = new PNM(image.Width, image.Height); // Apply zero crossing except last row and last column Parallel.For(0, image.Height - 1, i => { for (int j = 0; j < image.Width - 1; j++) { byte r = 0; byte g = 0; byte b = 0; // current index position int position = i * image.Width + j; float currentR = LoGRaster.Item1[position]; float neighbourR = LoGRaster.Item1[position + image.Width + 1]; float currentG = LoGRaster.Item2[position]; float neighbourG = LoGRaster.Item2[position + image.Width + 1]; float currentB = LoGRaster.Item3[position]; float neighbourB = LoGRaster.Item3[position + image.Width + 1]; if ((currentR * neighbourR) < 0 && (Math.Abs(currentR) < Math.Abs(neighbourR))) r = 255; if ((currentG * neighbourG) < 0 && (Math.Abs(currentG) < Math.Abs(neighbourG))) g = 255; if ((currentB * neighbourB) < 0 && (Math.Abs(currentB) < Math.Abs(neighbourB))) b = 255; returnImage.SetPixel(position, r, g, b); } }); return returnImage; }
public static Pixel Oil(PNM image, int index) { int length = 7; int padding = length / 2; byte[] rvalues = new byte[length * length]; byte[] gvalues = new byte[length * length]; byte[] bvalues = new byte[length * length]; byte r, g, b; int i = 0; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out r, out g, out b); rvalues[i] = r; gvalues[i] = g; bvalues[i] = b; i++; } } return new Pixel(rvalues.GroupBy(p => p).OrderByDescending(gr => gr.Count()).First().Key, gvalues.GroupBy(p => p).OrderByDescending(gr => gr.Count()).First().Key, bvalues.GroupBy(p => p).OrderByDescending(gr => gr.Count()).First().Key); }
private static PNM ApplyHysteresis(byte[] suppressed, int width, int height, double low, double high) { PNM image = new PNM(width, height); byte lowValue = (byte)(low*255); byte highValue = (byte)(high*255); for (int i = 0; i < suppressed.Length; i++) { if (suppressed[i] >= highValue) { image.SetPixel(i, 255, 255, 255); HysteresisConnect(image, i, width, height, lowValue, highValue); } } return image; }
public static Pixel Roberts(PNM image, int index) { return ConvoluteWithModule(image, index, RobertsX, RobertsY, 3, 1); }
public static Pixel Prewitt(PNM image, int index) { return ConvoluteWithModule(image, index, PrewittX, PrewittY, 3, 1); }
private static PNM DrawRectangles(PNM image, Tuple<float, float>[][] corners) { using (Bitmap bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb)) { BitmapData data = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] stridedBuffer = Lines.Stride(image.raster, image.Width, image.Height); Marshal.Copy(stridedBuffer, 0, data.Scan0, stridedBuffer.Length); bitmap.UnlockBits(data); using (Graphics graphics = Graphics.FromImage(bitmap)) { // draw the lines foreach (var corner in corners) { for (int i = 0; i < 4; i++) for (int j = i + 1; j < 4; j++ ) graphics.DrawLine(Pens.Blue, corner[i].Item1, corner[i].Item2, corner[j].Item1, corner[j].Item2); } } // get raw data PNM rectImage = new PNM(image.Width, image.Height); data = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); rectImage.raster = Lines.UnStride(data.Scan0, image.Width, image.Height); bitmap.UnlockBits(data); return rectImage; } }
public static Pixel Roberts(PNM image, int index) { return(ConvoluteWithModule(image, index, RobertsX, RobertsY, 3, 1)); }
public static Pixel ToGrayscale(byte r, byte g, byte b) { byte value = PNM.RGBToLuminosity(r, g, b); return(new Pixel(value, value, value)); }
public static Func <PNM, int, Pixel> GenerateFishEye(PNM image) { double maxR = Math.Sqrt(Math.Pow(image.Width / 2d, 2) + Math.Pow(image.Height / 2d, 2)); return((img, idx) => FishEye(img, idx, maxR)); }
public static Pixel Negative(PNM image, int index) { byte r, g, b; image.GetPixel(index, out r, out g, out b); return new Pixel((byte)(255 - r), (byte)(255 - g), (byte)(255 - b)); }
// assume k = -0.2 and R = 15x15 // needs 1 pixel width padding public static Pixel Niblack(PNM image, int index, double k = -0.2, int length = 15, int padding = 7) { byte r, g, b; float[] surrounding = new float[length * length]; int i = 0; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out r, out g, out b); surrounding[i] = PNM.RGBToLuminosity(r, g, b); i++; } } float mean = surrounding.Average(); double threshold = mean + (k* (mean / surrounding.Length)); image.GetPixel(index, out r, out g, out b); byte luminosity = PNM.RGBToLuminosity(r,g,b); if (luminosity < threshold) return Pixel.Black; return Pixel.White; }
public static Pixel Prewitt(PNM image, int index) { return(ConvoluteWithModule(image, index, PrewittX, PrewittY, 3, 1)); }
public static Func<PNM,int,Pixel> GenerateFishEye(PNM image) { double maxR = Math.Sqrt(Math.Pow(image.Width / 2d, 2) + Math.Pow(image.Height / 2d, 2)); return (img, idx) => FishEye(img, idx, maxR); }
// Kapur's method public static Func<byte, byte, byte, Pixel> Entropy(PNM image) { double[] histogram = image.GetHistogramLuminosity(); double entropySum = Double.NegativeInfinity; int threshold = 0; for (int i = 0; i < 256; i++) { double[] background = histogram.Take(i + 1).ToArray(); double[] foreground = histogram.Skip(i + 1).ToArray(); double sumB = background.Sum(); double sumF = foreground.Sum(); double entropyB = -background.Select(p => { if(p == 0) return 0; return (p / sumB) * Math.Log(p / sumB, 2); }) .Sum(); double entropyF = -foreground.Select(p => { if(p == 0) return 0; return (p / (1 - sumB)) * Math.Log(p / (1 - sumB), 2); }) .Sum(); double sum = entropyB + entropyF; if (sum > entropySum) { entropySum = sum; threshold = i; } } return (r, g, b) => Plain(r, g, b, (byte)threshold); }
internal static Pixel ConvoluteWithModule(PNM image, int index, float[] matrix1, float[] matrix2, int length, int padding) { float sumR1 = 0; float sumR2 = 0; float sumG1 = 0; float sumG2 = 0; float sumB1 = 0; float sumB2 = 0; byte r, g, b; for (int m = 0; m < length; m++) { for (int n = 0; n < length; n++) { image.GetPixel(index - ((padding - m) * image.Width) - (padding - n), out r, out g, out b); float coeff1 = matrix1[(m * length) + n]; float coeff2 = matrix2[(m * length) + n]; sumR1 += r * coeff1; sumR2 += r * coeff2; sumG1 += g * coeff1; sumG2 += g * coeff2; sumB1 += b * coeff1; sumB2 += b * coeff2; } } return new Pixel(Filter.Coerce(Module(sumR1, sumR2)), Filter.Coerce(Module(sumG1, sumG2)), Filter.Coerce(Module(sumB1, sumB2))); }
private static IEnumerable <Tuple <float, float>[]> MaskedHoughVote(PNM image, int center, bool[] mask, int dmax, int dmin, int padding) { double angleStep = (Math.PI * 3) / (4d * dmax); int angles = (int)Math.Floor(Math.PI / angleStep); double distanceStep = 3 / 4d; int distances = (int)Math.Ceiling(dmax / distanceStep); int[][] votingBoard = new int[angles][]; for (int i = 0; i < angles; i++) { votingBoard[i] = new int[distances]; } int maskSize = mask.Length; int maskIndex = 0; for (int i = -dmax / 2; i <= dmax / 2; i++) { for (int j = -dmax / 2; j <= dmax / 2; j++) { if (!mask[maskIndex++]) { continue; } int x = center % image.Width + i; int y = center / image.Width - j; int realIndex = (y * image.Width) + x; byte l; image.GetPixel(realIndex, out l, out l, out l); if (l < 255) { continue; } for (int angle = 0; angle < angles; angle++) { double radianAngle = angle * angleStep; double w = i * Math.Cos(radianAngle) + j * Math.Sin(radianAngle); double normalizedW = w + (dmax / 2d); int steppedW = (int)(normalizedW / distanceStep); votingBoard[angle][steppedW]++; } } } // votingboard is full - enhance it now List <double[]> peaks = EnhanceHoughVotingBoard(votingBoard, dmax, dmin, angleStep, distanceStep); List <Tuple <int, int, double> > extendedPeaks = new List <Tuple <int, int, double> >(peaks.Count / 2); for (int i = 0; i < peaks.Count; i++) { for (int j = i + 1; j < peaks.Count; j++) { if (Math.Abs(peaks[i][0] - peaks[j][0]) < AngularThreshold && Math.Abs(peaks[i][1] + peaks[j][1]) < DistanceThreshold && Math.Abs(peaks[i][2] - peaks[j][2]) < NormalizedThreshold * (peaks[i][2] + peaks[j][2]) / 2) { extendedPeaks.Add(Tuple.Create(i, j, 0.5 * (peaks[i][0] + peaks[j][0]))); } } } // extendedPeaks now holds Tuples of (i, j, ak), where i and j are indices of paired peaks and their alpha_k List <Tuple <double[][], double[][]> > finalPairs = new List <Tuple <double[][], double[][]> >(); for (int i = 0; i < extendedPeaks.Count; i++) { for (int j = i + 1; j < extendedPeaks.Count; j++) { if (Math.Abs(Math.Abs(extendedPeaks[i].Item3 - extendedPeaks[j].Item3) - (Math.PI / 2)) < AngularThreshold) { // we got pairs of peak pairs finalPairs.Add(Tuple.Create(new double[][] { peaks[extendedPeaks[i].Item1], peaks[extendedPeaks[i].Item2] }, new double[][] { peaks[extendedPeaks[j].Item1], peaks[extendedPeaks[j].Item2] })); } } } return(finalPairs.Select(pair => new Tuple <double, double>[] { PolarLineIntersection(pair.Item1[0][0], pair.Item1[0][1], pair.Item2[0][0], pair.Item2[0][1]), PolarLineIntersection(pair.Item1[1][0], pair.Item1[1][1], pair.Item2[0][0], pair.Item2[0][1]), PolarLineIntersection(pair.Item1[0][0], pair.Item1[0][1], pair.Item2[1][0], pair.Item2[1][1]), PolarLineIntersection(pair.Item1[1][0], pair.Item1[1][1], pair.Item2[1][0], pair.Item2[1][1]) }) .Select(tups => new Tuple <float, float>[] { CorrectCoordinates(tups[0].Item1, tups[0].Item2, center, image.Width, image.Height, padding), CorrectCoordinates(tups[1].Item1, tups[1].Item2, center, image.Width, image.Height, padding), CorrectCoordinates(tups[2].Item1, tups[2].Item2, center, image.Width, image.Height, padding), CorrectCoordinates(tups[3].Item1, tups[3].Item2, center, image.Width, image.Height, padding) })); }
internal static int[][] HoughVote(PNM image, int maxW) { // initialize voting board int[][] votingBoard = new int[180][]; for (int i = 0; i < 180; i++) votingBoard[i] = new int[maxW * 2]; int size = image.Width * image.Height; for (int i = 0; i < size; i++) { byte l; image.GetPixel(i, out l, out l, out l); if (l < 255) continue; double centeredX = i % image.Width - (image.Width / 2d); double centeredY = (image.Height / 2d) - i / image.Width; // pixel is white - vote in all directions for (int angle = 0; angle < 180; angle++) { double radianAngle = Math.PI * angle / 180d; double w = centeredX * Math.Cos(radianAngle) + centeredY * Math.Sin(radianAngle); votingBoard[angle][(int)w + maxW]++; } } return votingBoard; }
public static Pixel Sobel(PNM image, int index) { return ConvoluteWithModule(image, index, SobelX, SobelY, 3, 1); }
public static Pixel Sobel(PNM image, int index) { return(ConvoluteWithModule(image, index, SobelX, SobelY, 3, 1)); }
private static IEnumerable<Tuple<float, float>[]> MaskedHoughVote(PNM image, int center, bool[] mask, int dmax, int dmin, int padding) { double angleStep = (Math.PI * 3) / (4d * dmax); int angles = (int)Math.Floor(Math.PI / angleStep); double distanceStep = 3/4d; int distances = (int)Math.Ceiling(dmax / distanceStep); int[][] votingBoard = new int[angles][]; for (int i = 0; i < angles; i++) votingBoard[i] = new int[distances]; int maskSize = mask.Length; int maskIndex = 0; for (int i = -dmax/2; i <= dmax/2; i++) { for (int j = -dmax / 2; j <= dmax/2; j++) { if (!mask[maskIndex++]) continue; int x = center % image.Width + i; int y = center / image.Width - j; int realIndex = (y * image.Width) + x; byte l; image.GetPixel(realIndex, out l, out l, out l); if (l < 255) continue; for (int angle = 0; angle < angles; angle++) { double radianAngle = angle * angleStep; double w = i * Math.Cos(radianAngle) + j * Math.Sin(radianAngle); double normalizedW = w + (dmax / 2d); int steppedW = (int)(normalizedW / distanceStep); votingBoard[angle][steppedW]++; } } } // votingboard is full - enhance it now List<double[]> peaks = EnhanceHoughVotingBoard(votingBoard, dmax, dmin, angleStep, distanceStep); List<Tuple<int, int, double>> extendedPeaks = new List<Tuple<int, int, double>>(peaks.Count / 2); for (int i = 0; i < peaks.Count; i++) { for (int j = i + 1; j < peaks.Count; j++) { if (Math.Abs(peaks[i][0] - peaks[j][0]) < AngularThreshold && Math.Abs(peaks[i][1] + peaks[j][1]) < DistanceThreshold && Math.Abs(peaks[i][2] - peaks[j][2]) < NormalizedThreshold * (peaks[i][2] + peaks[j][2]) / 2) extendedPeaks.Add(Tuple.Create(i, j, 0.5 * (peaks[i][0] + peaks[j][0]))); } } // extendedPeaks now holds Tuples of (i, j, ak), where i and j are indices of paired peaks and their alpha_k List<Tuple<double[][], double[][]>> finalPairs = new List<Tuple<double[][], double[][]>>(); for (int i = 0; i < extendedPeaks.Count; i++) { for (int j = i + 1; j < extendedPeaks.Count; j++) { if (Math.Abs(Math.Abs(extendedPeaks[i].Item3 - extendedPeaks[j].Item3) - (Math.PI / 2)) < AngularThreshold) // we got pairs of peak pairs finalPairs.Add(Tuple.Create( new double[][] {peaks[extendedPeaks[i].Item1], peaks[extendedPeaks[i].Item2] }, new double[][] { peaks[extendedPeaks[j].Item1], peaks[extendedPeaks[j].Item2] })); } } return finalPairs.Select(pair => new Tuple<double, double>[] { PolarLineIntersection(pair.Item1[0][0], pair.Item1[0][1], pair.Item2[0][0], pair.Item2[0][1]), PolarLineIntersection(pair.Item1[1][0], pair.Item1[1][1], pair.Item2[0][0], pair.Item2[0][1]), PolarLineIntersection(pair.Item1[0][0], pair.Item1[0][1], pair.Item2[1][0], pair.Item2[1][1]), PolarLineIntersection(pair.Item1[1][0], pair.Item1[1][1], pair.Item2[1][0], pair.Item2[1][1])}) .Select(tups => new Tuple<float, float>[]{ CorrectCoordinates(tups[0].Item1, tups[0].Item2, center, image.Width, image.Height, padding), CorrectCoordinates(tups[1].Item1, tups[1].Item2, center, image.Width, image.Height, padding), CorrectCoordinates(tups[2].Item1, tups[2].Item2, center, image.Width, image.Height, padding), CorrectCoordinates(tups[3].Item1, tups[3].Item2, center, image.Width, image.Height, padding)}); }