public static BitmapSource Stretch(IImageStatistics statistics, Bitmap img, System.Windows.Media.PixelFormat pf, double factor, double blackClipping) { using (MyStopWatch.Measure()) { var filter = ImageUtility.GetColorRemappingFilter(statistics, factor, blackClipping, pf); filter.ApplyInPlace(img); var source = ImageUtility.ConvertBitmap(img, pf); source.Freeze(); return(source); } }
public static ColorRemappingGeneral GetColorRemappingFilterUnlinked( IImageStatistics redStatistics, IImageStatistics greenStatistics, IImageStatistics blueStatistics, double targetHistogramMeanPct, double shadowsClipping, System.Windows.Media.PixelFormat pf) { ushort[] mapRed = GetStretchMap(redStatistics, targetHistogramMeanPct, shadowsClipping); ushort[] mapGreen = GetStretchMap(greenStatistics, targetHistogramMeanPct, shadowsClipping); ushort[] mapBlue = GetStretchMap(blueStatistics, targetHistogramMeanPct, shadowsClipping); if (pf == PixelFormats.Rgb48) { var filter = new ColorRemappingGeneral(mapRed, mapGreen, mapBlue); return(filter); } else { throw new NotSupportedException(); } }
public static ColorRemappingGeneral GetColorRemappingFilter( IImageStatistics statistics, double targetHistogramMeanPct, double shadowsClipping, System.Windows.Media.PixelFormat pf) { ushort[] map = GetStretchMap(statistics, targetHistogramMeanPct, shadowsClipping); if (pf == PixelFormats.Gray16) { var filter = new ColorRemappingGeneral(map); return(filter); } else if (pf == PixelFormats.Rgb48) { var filter = new ColorRemappingGeneral(map, map, map); return(filter); } else { throw new NotSupportedException(); } }
private static ushort[] GetStretchMap(IImageStatistics statistics, double targetHistogramMedianPercent, double shadowsClipping) { ushort[] map = new ushort[ushort.MaxValue + 1]; var normalizedMedian = NormalizeUShort(statistics.Median); var normalizedMAD = NormalizeUShort(statistics.MedianAbsoluteDeviation); var scaleFactor = 1.4826; // see https://en.wikipedia.org/wiki/Median_absolute_deviation double shadows = 0d; double midtones = 0.5d; double highlights = 1d; //Assume the image is inverted or overexposed when median is higher than half of the possible value if (normalizedMedian > 0.5) { shadows = 0d; highlights = normalizedMedian - shadowsClipping * normalizedMAD * scaleFactor; midtones = MidtonesTransferFunction(highlights - normalizedMedian, targetHistogramMedianPercent); } else { shadows = normalizedMedian + shadowsClipping * normalizedMAD * scaleFactor; midtones = MidtonesTransferFunction(targetHistogramMedianPercent, normalizedMedian - shadows); highlights = 1; } for (int i = 0; i < map.Length; i++) { double value = NormalizeUShort(i); map[i] = DenormalizeUShort(MidtonesTransferFunction(midtones, 1 - highlights + value - shadows)); } return(map); }