I have an array of BitmapFrames and need to do a histogram stretch. I know this is different from a histogram equalization, and what the final outcome is... sorta. the problem is I have absolutely no idea what to do after I get the histogram.
So far my code creates an array for the histogram so I know how many pixels of each value i have. But after that I don't know what to do.
this is the code I have so far... right now it makes the histogram and then histogram equalizes... which is NOT what I want... I was just trying to learn more about histograms
[Cmdlet(VerbsData.ConvertTo, "HistoStretch")]
public class HistoStretchCmdlet : PSCmdlet
{
private BitmapFrame[] bFrame, outFrame;
private BitmapSource src;
private double pixelsize;
private byte[] pixels, outPixels;
private byte MAX_VAL;
private int[] histogram;
private int cf, start;
[Parameter(ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true), ValidateNotNullOrEmpty]
public BitmapFrame[] Bitmap
{
get
{
return bFrame;
}
set
{
bFrame = value;
}
}
protected override void ProcessRecord()
{
base.ProcessRecord();
Console.Write("Applying a histogram stretch to the image...\n\n");
outFrame = new BitmapFrame[bFrame.Length];
for (int c = 0; c < bFrame.Length; c++)
{
MAX_VAL = (byte)((1 << bFrame[c].Format.BitsPerPixel) - 1);
histogram = new int[MAX_VAL + 1];
for (int i = 0; i <= MAX_VAL; i++)
{
histogram[i] = 0;
}
pixelsize = bFrame[c].PixelWidth * bFrame[c].PixelHeight;
pixels = new byte[(int)pixelsize];
outPixels = new byte[(int)pixelsize];
bFrame[c].CopyPixels(pixels,(int)bFrame[c].Width * (bFrame[c].Format.BitsPerPixel / 8),0);
for (int i = 0; i < pixelsize; i++)
{
histogram[(int)pixels[i]] = histogram[(int)pixels[i]] + 1;
}
for (int i = 0; i <= MAX_VAL; i++)
{
Console.Write("{0}: {1}\n", i, histogram[i]);
}
for (int i = 0; i <= MAX_VAL; i++)
{
if (histogram[i] >= 1)
{
start = i;
break;
}
}
for (int i = 0; i < pixelsize; i++)
{
cf = 0;
for (int g = 0; g <= MAX_VAL; g++)
{
cf += histogram[g];
if (g == pixels[i])
{
break;
}
}
outPixels[i] = (byte)(cf * (MAX_VAL / pixelsize));
}
src = BitmapSource.Create(bFrame[c].PixelWidth, bFrame[c].PixelHeight, bFrame[c].DpiX, bFrame[c].DpiY,
bFrame[c].Format, bFrame[c].Palette, outPixels, (int)(bFrame[c].Width * (bFrame[c].Format.BitsPerPixel / 8)));
outFrame[c] = BitmapFrame.Create(src);
}
WriteObject(outFrame);
}
}
this is what the histograms should look like according to my teacher:
http://www.fileden.com/files/2009/8/18/2547657/histostretch.PNG
I ran the code above... and got a straight black image. here's my code:
outFrame = new BitmapFrame[bFrame.Length];
for (int c = 0; c < bFrame.Length; c++)
{
MAX_VAL = (byte)((1 << bFrame[c].Format.BitsPerPixel) - 1);
histogram = new int[MAX_VAL + 1];
for (int i = 0; i <= MAX_VAL; i++)
{
histogram[i] = 0;
}
pixelsize = bFrame[c].PixelWidth * bFrame[c].PixelHeight;
pixels = new byte[(int)pixelsize];
outPixels = new byte[(int)pixelsize];
bFrame[c].CopyPixels(pixels,(int)bFrame[c].Width * (bFrame[c].Format.BitsPerPixel / 8),0);
max = pixels[0];
min = pixels[0];
for (int i = 0; i < pixelsize; i++)
{
histogram[(int)pixels[i]] = histogram[(int)pixels[i]] + 1;
if((int)pixels[i] > max)
max = pixels[i];
if((int)pixels[i] < min)
min = pixels[i];
}
dynamic = max - min;
for (int i = 0; i < pixelsize; i++)
{
outPixels[i] = (byte)(((pixels[i] - min) / dynamic) * MAX_VAL);
}
With a simple linear stretch, the minimum and maximum histogram values define the dynamic range of the image. You can set these values by clicking the Histogram Stretch button in the main toolbar. When you adjust these two points, pixel values greater than the maximum histogram value are assigned a value of 255.
Histogram stretching involves modifying the brightness (intensity) values of pixels in the image according to some mapping function that specifies an output pixel brightness value for each input pixel brightness value. For a grayscale digital image, this process is straightforward.
Histogram stretching is the mapping of pixel values such that:
In other words histogram stretching means stretching the dynamic of the image data (84:153) to the greatest possible dynamic (0:255).
This should not affect the hight of the histogram peaks, but only their spread (the illustration is a bit misleading on this point).
histogram stretch http://cct.rncan.gc.ca/resource/tutor/fundam/images/linstre.gif
Image source
In practice this is the mapping you would apply to the pixels of the image (pseudocode):
maxVal = image.maximumValue() # 153
minVal = image.minumumValue() # 84
dynamic = maxVal-minVal
for pixel in image.Pixels():
newPixel = ((pixel-minVal)/dynamic)*255
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With