/* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ using System; using System.Drawing; namespace HistogramTest { /// <summary> /// Compares 2 images using normalized histogram equalization /// compare method, see: http://en.wikipedia.org/wiki/Histogram_equalization /// </summary> class ImageHistogram { Bitmap image = null; int[] mapR = null; int[] mapG = null; int[] mapB = null; double[] mapNormalR = null; double[] mapNormalG = null; double[] mapNormalB = null; protected Color[] histogramEqualizationTable = null; public ImageHistogram(Bitmap bitmapIn) { image = bitmapIn; calculateHistogram(); calculateHistogramEqualizationTable(); } public override bool Equals(Object other) { ImageHistogram ih = other as ImageHistogram; if (ih == null) return false; return (this.CalculateDifference(ih) == 0); } public override int GetHashCode() { if (image == null) return 0; return image.GetHashCode(); } public double CalculateConfidencePercent(ImageHistogram other) { if (image == null) return 0.0; int difference = CalculateDifference(other); int maxPossibleError = 256 * 256; double confidence = 1.0 - ((double)difference / (double)maxPossibleError); return confidence; } public int CalculateDifference(ImageHistogram other) { if ((this.image == null) || (other.image == null)) return 1000000; byte valueR; byte valueG; byte valueB; byte valueROther; byte valueGOther; byte valueBOther; int totalDistance = 0; for (int i = 0; i < 256; i++) { Color color = histogramEqualizationTable[i]; valueR = color.R; valueG = color.G; valueB = color.B; Color colorOther = other.histogramEqualizationTable[i]; valueROther = colorOther.R; valueGOther = colorOther.G; valueBOther = colorOther.B; int deltaR = Math.Abs((int)(valueR - valueROther)); int deltaG = Math.Abs((int)(valueG - valueGOther)); int deltaB = Math.Abs((int)(valueB - valueBOther)); totalDistance += deltaR; totalDistance += deltaG; totalDistance += deltaB; } return totalDistance; } private void calculateHistogram() { byte valueR; byte valueG; byte valueB; byte valueAlpha; mapR = new int[256]; mapG = new int[256]; mapB = new int[256]; for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { Color pixelColor = image.GetPixel(x, y); valueR = pixelColor.R; valueG = pixelColor.G; valueB = pixelColor.B; valueAlpha = pixelColor.A; // Implementation Specific Change to Standard Histogram Compare Here: if (((valueR == 255) && (valueG == 255) && (valueB == 255)) || (valueAlpha == 0)) // TRICKY: Don't count whites or transparents (background colors in this case) // NOTE: this will affect the correctness if an image really has white/transparent in it // since these are ignored continue; mapR[valueR] = mapR[valueR] + 1; mapG[valueG] = mapG[valueG] + 1; mapB[valueB] = mapB[valueB] + 1; } } // Normalize the histogram double size = (double)(image.Height * image.Width); mapNormalR = new double[256]; mapNormalG = new double[256]; mapNormalB = new double[256]; for (int i = 0; i < 256; i++) { mapNormalR[i] = mapR[i] / size; mapNormalG[i] = mapG[i] / size; mapNormalB[i] = mapB[i] / size; } } private void calculateHistogramEqualizationTable() { histogramEqualizationTable = new Color[256]; double sumR = 0.0; double sumG = 0.0; double sumB = 0.0; // Compute the CDF for (int i = 0; i < 256; i++) { sumR += mapNormalR[i]; sumG += mapNormalG[i]; sumB += mapNormalB[i]; histogramEqualizationTable[i] = Color.FromArgb((int)(sumR * 255.0 + 0.5), (int)(sumG * 255.0 + 0.5), (int)(sumB * 255.0 + 0.5)); } } } }