Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I need to do a histogram stretch

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);
            }
like image 225
dabonz413 Avatar asked Aug 18 '09 16:08

dabonz413


People also ask

How do you stretch a histogram?

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.

What is the purpose of histogram stretching?

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.


1 Answers

Histogram stretching is the mapping of pixel values such that:

  • the lowest value (e.g. 84 in the illustration) becomes 0
  • the highest value (e.g. 153 in the illustration) becomes 255 (in 8bit images)
  • and all the intermediate values are interpolated between that range (see illustration).

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
like image 63
Ivan Avatar answered Sep 23 '22 14:09

Ivan